Compare commits
718 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
42da871d93 | ||
|
|
03032d0c72 | ||
|
|
d690d9c1bf | ||
|
|
99cc2448f7 | ||
|
|
99b673dfa5 | ||
|
|
b4bff5db90 | ||
|
|
354ed7e5e4 | ||
|
|
5ecc5bbae9 | ||
|
|
d069bbeefe | ||
|
|
eb806b62bf | ||
|
|
6dd51170bb | ||
|
|
76b941933e | ||
|
|
71a627c099 | ||
|
|
a21af1016e | ||
|
|
85585c42c0 | ||
|
|
175da8b515 | ||
|
|
ccc73e3790 | ||
|
|
786b11ad46 | ||
|
|
332a25f241 | ||
|
|
12b08a975f | ||
|
|
2058eba1fb | ||
|
|
d7846b31a2 | ||
|
|
3c81d0ee55 | ||
|
|
0898078cc8 | ||
|
|
69124a74e8 | ||
|
|
4325b6d139 | ||
|
|
66eca437b8 | ||
|
|
8837d4a0d8 | ||
|
|
61a7f2e936 | ||
|
|
45cc6b9728 | ||
|
|
173def3cea | ||
|
|
2b1cd74f6a | ||
|
|
e1c18a3ea8 | ||
|
|
eb9de532f1 | ||
|
|
a1ed825835 | ||
|
|
cc3ce5679e | ||
|
|
b686b17e0a | ||
|
|
c6d28246ea | ||
|
|
f4f071551f | ||
|
|
ec4378ca49 | ||
|
|
d031afdbc4 | ||
|
|
61d0a41103 | ||
|
|
07f2d08981 | ||
|
|
9609774b3a | ||
|
|
8d9a613835 | ||
|
|
678fb81ed5 | ||
|
|
af5ce97b75 | ||
|
|
2c78e36ebd | ||
|
|
162eb3d649 | ||
|
|
ef6b63c82f | ||
|
|
c015012783 | ||
|
|
6b80f75ec8 | ||
|
|
bdcdddf465 | ||
|
|
2a0e0f5e28 | ||
|
|
888b84aee2 | ||
|
|
8b1149255d | ||
|
|
2913751beb | ||
|
|
1c2af5a60f | ||
|
|
fde88c10c5 | ||
|
|
21290f5752 | ||
|
|
194642314e | ||
|
|
d7d8903fee | ||
|
|
ce4de49d50 | ||
|
|
b130231f4e | ||
|
|
7ce0d99526 | ||
|
|
c6a6d952e6 | ||
|
|
6cd8f79e8b | ||
|
|
9433f60557 | ||
|
|
6992ea5250 | ||
|
|
a06af14dd9 | ||
|
|
68376581a0 | ||
|
|
eb47dcadd4 | ||
|
|
36db2ff0eb | ||
|
|
046bb0e9ff | ||
|
|
0dc4dd4a93 | ||
|
|
cb74f6ca55 | ||
|
|
1a0f6bb6ce | ||
|
|
091797f9b7 | ||
|
|
5611c8ad24 | ||
|
|
ae54ea01d0 | ||
|
|
1db9232d71 | ||
|
|
5dcfe18748 | ||
|
|
558ea65aa1 | ||
|
|
0d44b10734 | ||
|
|
c1744e9e6f | ||
|
|
2fd9e4b993 | ||
|
|
44682659b6 | ||
|
|
148c302474 | ||
|
|
6037b85f4b | ||
|
|
bd7428485c | ||
|
|
3df38fcff5 | ||
|
|
7219906306 | ||
|
|
7e0917c2cd | ||
|
|
0df634a586 | ||
|
|
1a8285fcf0 | ||
|
|
fc4e1802f6 | ||
|
|
19a177485d | ||
|
|
00aaea935c | ||
|
|
6a3d82c60a | ||
|
|
4c98c24047 | ||
|
|
a17a66af00 | ||
|
|
9433050588 | ||
|
|
49b9a07a95 | ||
|
|
f407beab99 | ||
|
|
fa81fc222f | ||
|
|
649989fd83 | ||
|
|
f7ef126d97 | ||
|
|
e4f63e8f15 | ||
|
|
3cfd12b0bc | ||
|
|
94b01420af | ||
|
|
ec86a19fc6 | ||
|
|
e0cbe59a10 | ||
|
|
8f94c038d8 | ||
|
|
a4b334b6f2 | ||
|
|
9708019adc | ||
|
|
5a6a4f02d9 | ||
|
|
75057023cb | ||
|
|
d839a35340 | ||
|
|
d5a478f64a | ||
|
|
e5f3fb13ae | ||
|
|
0d8890defd | ||
|
|
016e12720d | ||
|
|
d25a926226 | ||
|
|
09fc43349f | ||
|
|
b3e305fd14 | ||
|
|
d763fad449 | ||
|
|
e877bb26c3 | ||
|
|
28fad62ccd | ||
|
|
f9d8595a25 | ||
|
|
3bf28cd427 | ||
|
|
c3032579c0 | ||
|
|
867db19bc5 | ||
|
|
cfa6a217be | ||
|
|
520ff72395 | ||
|
|
25df8b66fc | ||
|
|
d632135289 | ||
|
|
a3d443268a | ||
|
|
d03e319e35 | ||
|
|
165ec25713 | ||
|
|
35c93ee6f5 | ||
|
|
cc90426d94 | ||
|
|
6db5348daa | ||
|
|
9bf073156f | ||
|
|
8f50375cf2 | ||
|
|
451f4c1b69 | ||
|
|
95aa544275 | ||
|
|
eab73c81a7 | ||
|
|
cfc01ac9fc | ||
|
|
64d2527190 | ||
|
|
b48f1e9af5 | ||
|
|
6cfea5aca3 | ||
|
|
d06c1e5f5b | ||
|
|
2cc47b0117 | ||
|
|
884cc6f8f1 | ||
|
|
2629449436 | ||
|
|
0a7e1f4185 | ||
|
|
5fdff65281 | ||
|
|
f7ccf338ad | ||
|
|
feb476c76b | ||
|
|
b258a93750 | ||
|
|
d07441e7fa | ||
|
|
6564d1a0c5 | ||
|
|
41af615428 | ||
|
|
4ea1bb9c43 | ||
|
|
c3cabe43bf | ||
|
|
6ff403fad1 | ||
|
|
b73afe0da9 | ||
|
|
be43b0ab3c | ||
|
|
24f3106fe7 | ||
|
|
1b6144a78c | ||
|
|
948ea5fa00 | ||
|
|
d21a65e117 | ||
|
|
4564aebec1 | ||
|
|
840892288b | ||
|
|
47bcfb1299 | ||
|
|
d24e8f83c6 | ||
|
|
731aaf4203 | ||
|
|
746be11f3b | ||
|
|
5634b33d19 | ||
|
|
3a09e7d548 | ||
|
|
31aed9e793 | ||
|
|
4e558833a3 | ||
|
|
07c3678ea9 | ||
|
|
ef02247a0c | ||
|
|
d811b194eb | ||
|
|
9b10cab925 | ||
|
|
1e29b2047d | ||
|
|
8df1a12412 | ||
|
|
d853d8594a | ||
|
|
c3a8c411a5 | ||
|
|
d388e1cf03 | ||
|
|
ea93e69d5c | ||
|
|
4ec634ccfd | ||
|
|
fa7fcc8c3b | ||
|
|
8eca6249c0 | ||
|
|
3d9b2b2c1c | ||
|
|
658d5f5b71 | ||
|
|
9224e2b3e6 | ||
|
|
c395fa3f0f | ||
|
|
f74eb8c88a | ||
|
|
1025c80ef5 | ||
|
|
313032aa41 | ||
|
|
a611aee899 | ||
|
|
0dff23d42b | ||
|
|
0a27b2ea10 | ||
|
|
fa60b9a80a | ||
|
|
f0ac68e369 | ||
|
|
11bc8e5df2 | ||
|
|
3df5d6d0b4 | ||
|
|
ef2228cf29 | ||
|
|
a9b5259a08 | ||
|
|
3525caedd1 | ||
|
|
943e94ed0e | ||
|
|
96ce620f69 | ||
|
|
1458a482d0 | ||
|
|
fd548121c2 | ||
|
|
05943767e5 | ||
|
|
2fa0a43e4c | ||
|
|
fa34cd9be5 | ||
|
|
b6a8984ce0 | ||
|
|
176986d22a | ||
|
|
f2ae32b01d | ||
|
|
c141f7c105 | ||
|
|
5c9dc2cee8 | ||
|
|
3595662729 | ||
|
|
c98df21747 | ||
|
|
f0a792bd51 | ||
|
|
fa5e815912 | ||
|
|
6905113b49 | ||
|
|
45af5d96d9 | ||
|
|
ff0f1c8c77 | ||
|
|
d251b4de87 | ||
|
|
5cfc97386a | ||
|
|
c9e6d3ec33 | ||
|
|
5db5260ae8 | ||
|
|
6e3d97617f | ||
|
|
cf597ae09d | ||
|
|
846e7cb0aa | ||
|
|
a255d1131d | ||
|
|
16e85a297c | ||
|
|
535f1700bf | ||
|
|
5a85c97f3d | ||
|
|
5b52edd880 | ||
|
|
1ed87e571d | ||
|
|
bb1618faaf | ||
|
|
c03fc96f04 | ||
|
|
7b04309990 | ||
|
|
22fa1d4894 | ||
|
|
f9360fc94f | ||
|
|
953bc09bf3 | ||
|
|
c3c2c24254 | ||
|
|
51a1be19c8 | ||
|
|
7b9997b111 | ||
|
|
98a8e4f7f8 | ||
|
|
f85877fb72 | ||
|
|
18b1c65c7c | ||
|
|
0d6c7ece04 | ||
|
|
07dc3e4040 | ||
|
|
099c379272 | ||
|
|
f6d62301e7 | ||
|
|
c6bdf43d8d | ||
|
|
45955aec4a | ||
|
|
2865c72748 | ||
|
|
d4624e08bf | ||
|
|
102251b0bb | ||
|
|
40c98d5027 | ||
|
|
c8a127a8ed | ||
|
|
5c0bbde77b | ||
|
|
cd2454373a | ||
|
|
84218d55c3 | ||
|
|
665cfef8d3 | ||
|
|
43907a4001 | ||
|
|
66d052cee2 | ||
|
|
a2b1a999e5 | ||
|
|
5e69272ebc | ||
|
|
185d9708cd | ||
|
|
6138c535c9 | ||
|
|
392e479c59 | ||
|
|
15198fd9c2 | ||
|
|
3ee3f4f297 | ||
|
|
fb02d154e1 | ||
|
|
883b0f3ba4 | ||
|
|
6bff01a3b5 | ||
|
|
42d96d96fd | ||
|
|
819735efbf | ||
|
|
28cc8eef19 | ||
|
|
321bb186df | ||
|
|
91eea96308 | ||
|
|
486a89d407 | ||
|
|
5607280836 | ||
|
|
d878f56839 | ||
|
|
ca4261d8ca | ||
|
|
6eafce0082 | ||
|
|
752407fb67 | ||
|
|
4d30b3c951 | ||
|
|
1421da2aab | ||
|
|
4dcfcc2a84 | ||
|
|
8f50c5a3de | ||
|
|
8364815deb | ||
|
|
fc2852d1c1 | ||
|
|
9be3184f2a | ||
|
|
62d59d7762 | ||
|
|
bf2beb7431 | ||
|
|
ce8f1523cf | ||
|
|
32e0fe312b | ||
|
|
ad2fb175b3 | ||
|
|
04ba1aa1c5 | ||
|
|
dc4c25bff5 | ||
|
|
dc3b1ea8c7 | ||
|
|
2ac2f928c4 | ||
|
|
358e44a436 | ||
|
|
2f92a69bb0 | ||
|
|
6ca72c5751 | ||
|
|
4b48bdd3e5 | ||
|
|
cd3eb37ac8 | ||
|
|
e9296fd65a | ||
|
|
dda4a31149 | ||
|
|
02d82adf07 | ||
|
|
654d71abed | ||
|
|
5bcb075aa5 | ||
|
|
21ea0aff42 | ||
|
|
f6fa5b79ea | ||
|
|
d8104f4bf8 | ||
|
|
0516d3555a | ||
|
|
df8f87cc21 | ||
|
|
3019fd7ea3 | ||
|
|
5470fb6926 | ||
|
|
3eb7edc37c | ||
|
|
eef5fd987d | ||
|
|
757bfdc867 | ||
|
|
4237ed0d92 | ||
|
|
4929c8488c | ||
|
|
04e90fc905 | ||
|
|
64b56c593e | ||
|
|
ef84747de2 | ||
|
|
56fe22cc58 | ||
|
|
038e1b0881 | ||
|
|
ef278b0645 | ||
|
|
3c507d135f | ||
|
|
86155d5714 | ||
|
|
a1399d8c5c | ||
|
|
323327b0f2 | ||
|
|
710dd3cd7f | ||
|
|
4f83c466f0 | ||
|
|
955382eb8f | ||
|
|
4968e752e6 | ||
|
|
c8ff5bac96 | ||
|
|
afbf2cfc40 | ||
|
|
079c8e4e4c | ||
|
|
8c5f53d868 | ||
|
|
e6a2605c53 | ||
|
|
c1d8158ba5 | ||
|
|
6c510ebdb5 | ||
|
|
db81499eb8 | ||
|
|
b5d459be0d | ||
|
|
60b7beefa5 | ||
|
|
0d14294d79 | ||
|
|
818f82aaa5 | ||
|
|
54c2b3bd35 | ||
|
|
8be2df0f4b | ||
|
|
f34750a5ff | ||
|
|
5621f0dbe1 | ||
|
|
18efea4bad | ||
|
|
7a16d157f7 | ||
|
|
6d7ca472a3 | ||
|
|
0e5ffce862 | ||
|
|
ec5a8536be | ||
|
|
1ed131d925 | ||
|
|
74c45d5881 | ||
|
|
619db00c54 | ||
|
|
6d21dfdade | ||
|
|
38a1187cb7 | ||
|
|
2b6b001c0c | ||
|
|
f799cb3a34 | ||
|
|
00ea70e3bc | ||
|
|
684b9473d7 | ||
|
|
319fca0227 | ||
|
|
245c5a1392 | ||
|
|
92792ba71e | ||
|
|
817f36e80b | ||
|
|
3ba3354e9a | ||
|
|
98ac2a8035 | ||
|
|
72cd9d663e | ||
|
|
9c4a3ba8c4 | ||
|
|
b3ea49f7fd | ||
|
|
967c5e49c2 | ||
|
|
781a9e32ca | ||
|
|
f00af67283 | ||
|
|
b62f69a0ca | ||
|
|
407b5c644f | ||
|
|
89b866a611 | ||
|
|
0013e7fdb6 | ||
|
|
49961eb6cf | ||
|
|
54c54a23b7 | ||
|
|
beaa4b695c | ||
|
|
141b0ce6bc | ||
|
|
206e1eed4f | ||
|
|
1a42580826 | ||
|
|
6b4dfd578f | ||
|
|
630ef27436 | ||
|
|
6a8a5dc24a | ||
|
|
8f22bdef46 | ||
|
|
a2ea2df83a | ||
|
|
d37c7123d9 | ||
|
|
7ff10d141f | ||
|
|
839987727e | ||
|
|
c6dd1fb19b | ||
|
|
d1cbbc0213 | ||
|
|
d09c2f046b | ||
|
|
38dea9bb3e | ||
|
|
b86e78797e | ||
|
|
777f6e2406 | ||
|
|
33d7230a5f | ||
|
|
b71348a074 | ||
|
|
db9671e2df | ||
|
|
2e7183b8de | ||
|
|
30e4f59a16 | ||
|
|
17bec21ad1 | ||
|
|
d9559e7c59 | ||
|
|
77dfd78904 | ||
|
|
033a509541 | ||
|
|
df3d7ae536 | ||
|
|
36cce4f969 | ||
|
|
4666c24d59 | ||
|
|
468d7b2453 | ||
|
|
6ca554f4ad | ||
|
|
7cf4d527df | ||
|
|
da5b019b33 | ||
|
|
bb61b70417 | ||
|
|
43d5455e82 | ||
|
|
e6964b56d0 | ||
|
|
88218e097d | ||
|
|
46a129072f | ||
|
|
4abd2ab671 | ||
|
|
87ecee13e6 | ||
|
|
f2ab06f732 | ||
|
|
62eeba69e8 | ||
|
|
7d8eb6ffc7 | ||
|
|
dd2167a09f | ||
|
|
8e25c6c417 | ||
|
|
8d16a8312d | ||
|
|
b6d0a1541a | ||
|
|
a7c90cdac9 | ||
|
|
74fa4142d6 | ||
|
|
46b63b52b2 | ||
|
|
158bdfb418 | ||
|
|
1eb39d650a | ||
|
|
2e492ee9bc | ||
|
|
f10839b832 | ||
|
|
77034a46fe | ||
|
|
1c1eb3d08d | ||
|
|
bcce3cdfe7 | ||
|
|
af5e934d69 | ||
|
|
cc3d7f8b07 | ||
|
|
1ff8e11a1f | ||
|
|
a8ee018a16 | ||
|
|
08c6186fe4 | ||
|
|
e78200ee34 | ||
|
|
23c76417d2 | ||
|
|
58f51d07a2 | ||
|
|
9edd322a70 | ||
|
|
abdffb9a4f | ||
|
|
84dd3078d8 | ||
|
|
ed049e888d | ||
|
|
7e494f4bcb | ||
|
|
e1160114f6 | ||
|
|
e5eec3e97f | ||
|
|
c87bb409b5 | ||
|
|
7777c76dae | ||
|
|
34d1e2f251 | ||
|
|
d668da69fb | ||
|
|
1669f2c28f | ||
|
|
907b1b3ae2 | ||
|
|
e29c9043b2 | ||
|
|
6f3610e578 | ||
|
|
9a2b59ad78 | ||
|
|
1949b1fd48 | ||
|
|
6bf970e491 | ||
|
|
23050890e9 | ||
|
|
d3c1d0cd04 | ||
|
|
3faf183cb2 | ||
|
|
fafd8b5f22 | ||
|
|
373c1a3447 | ||
|
|
3d5cf24de4 | ||
|
|
1f8c8b8f61 | ||
|
|
9e94ed1cea | ||
|
|
01790af3c5 | ||
|
|
551ad7f6af | ||
|
|
b3fd4203d2 | ||
|
|
c462381587 | ||
|
|
99faafe723 | ||
|
|
efefecdbe3 | ||
|
|
fcb2b6bbf6 | ||
|
|
cce88ae3eb | ||
|
|
1616a58bd7 | ||
|
|
0fcb7903bb | ||
|
|
3db37023c7 | ||
|
|
e38bda7239 | ||
|
|
9a05f794f7 | ||
|
|
f943f41895 | ||
|
|
494f3fa199 | ||
|
|
0bb7fdd2eb | ||
|
|
650538ad2e | ||
|
|
b1debdf912 | ||
|
|
077de02345 | ||
|
|
163a770abc | ||
|
|
fc2a8e348c | ||
|
|
56278795ea | ||
|
|
a82f27ab8c | ||
|
|
2b8476ceca | ||
|
|
5ed4723535 | ||
|
|
b6aaa42337 | ||
|
|
e723604816 | ||
|
|
51ee9654da | ||
|
|
ea3fca3767 | ||
|
|
efad448fab | ||
|
|
018c993a9d | ||
|
|
863480acf2 | ||
|
|
ff12285e94 | ||
|
|
51b95f9cee | ||
|
|
86181525df | ||
|
|
85b6dc1766 | ||
|
|
bc7ad37e62 | ||
|
|
8042053331 | ||
|
|
0143dc25bf | ||
|
|
3e3ba60165 | ||
|
|
bd5c852fb6 | ||
|
|
a32f2d34f0 | ||
|
|
fee53e0ccf | ||
|
|
2eb58fb262 | ||
|
|
9ac6af95e3 | ||
|
|
b3da89d61c | ||
|
|
c91a79fe5b | ||
|
|
6771f59ab7 | ||
|
|
2faa2aeb95 | ||
|
|
04011a0a19 | ||
|
|
8ba3518fbc | ||
|
|
0849a75686 | ||
|
|
b33e73f119 | ||
|
|
549df19d4a | ||
|
|
100a9730d2 | ||
|
|
db35decac9 | ||
|
|
2810e56162 | ||
|
|
79e22b7d07 | ||
|
|
83ac8c9ac2 | ||
|
|
d3de97b584 | ||
|
|
f051962e81 | ||
|
|
723129b639 | ||
|
|
0183006c00 | ||
|
|
72b6565510 | ||
|
|
31adcd4728 | ||
|
|
fa4346cbc8 | ||
|
|
9d0c03be10 | ||
|
|
db999a58f2 | ||
|
|
a137686163 | ||
|
|
6016129562 | ||
|
|
a55e9ab3ba | ||
|
|
c5fd1c71be | ||
|
|
34ef8a5278 | ||
|
|
d808d8f157 | ||
|
|
259b453acb | ||
|
|
bc929b7c26 | ||
|
|
ffcf5fbf92 | ||
|
|
16eefa4abf | ||
|
|
49dfd7432c | ||
|
|
923103dec8 | ||
|
|
81a82aae64 | ||
|
|
d3500d38ba | ||
|
|
a950656112 | ||
|
|
c7d75b6b83 | ||
|
|
f5cf2b8de5 | ||
|
|
bd192b9af5 | ||
|
|
a412eef268 | ||
|
|
7d07e55ce5 | ||
|
|
e8c3e22dc6 | ||
|
|
cf12865aa0 | ||
|
|
2200972f4d | ||
|
|
c7c824c3c5 | ||
|
|
89ab458a5f | ||
|
|
bd7f94333d | ||
|
|
4de7a48e87 | ||
|
|
e3c8cc7fd9 | ||
|
|
4a9013d986 | ||
|
|
2910355245 | ||
|
|
23eb9a4dae | ||
|
|
59c158119a | ||
|
|
536367392f | ||
|
|
f982e756c2 | ||
|
|
29670af4d3 | ||
|
|
70b870690e | ||
|
|
1232c34817 | ||
|
|
9acae3b154 | ||
|
|
0233f383bb | ||
|
|
3bf7a09f98 | ||
|
|
5e1dc53304 | ||
|
|
e567067d44 | ||
|
|
518c256cc2 | ||
|
|
07f2ca5f16 | ||
|
|
d2cb8f2d9a | ||
|
|
b8d6c28ae4 | ||
|
|
c364f6a832 | ||
|
|
e2bf84f576 | ||
|
|
64b9774c83 | ||
|
|
ddd7003d89 | ||
|
|
437c983533 | ||
|
|
14b4df3836 | ||
|
|
b6cb0b2c7b | ||
|
|
81dfabbe15 | ||
|
|
3ec1b93f8e | ||
|
|
ee63c4e386 | ||
|
|
61a20cf27e | ||
|
|
a5db13c8b5 | ||
|
|
6147cda561 | ||
|
|
fcfb409282 | ||
|
|
d03d77aff8 | ||
|
|
637e0bb14c | ||
|
|
32ba61fb09 | ||
|
|
a9aa28ae77 | ||
|
|
99adb49736 | ||
|
|
21d242ba6a | ||
|
|
10d24c47ec | ||
|
|
604c30bf28 | ||
|
|
1d56759276 | ||
|
|
af77e984ab | ||
|
|
1af7bd842e | ||
|
|
7bd019fb28 | ||
|
|
bb9ea1849a | ||
|
|
cc449a49ea | ||
|
|
4c8bfb91eb | ||
|
|
3500211eed | ||
|
|
b65b63a9f0 | ||
|
|
87c86f8aeb | ||
|
|
c9b60445ca | ||
|
|
4ad3a884a6 | ||
|
|
f15a6dc491 | ||
|
|
7fb2193032 | ||
|
|
8df6eeb85a | ||
|
|
4ad5025c77 | ||
|
|
777fa30c76 | ||
|
|
f214de1407 | ||
|
|
e56741b669 | ||
|
|
559fbc0286 | ||
|
|
dcf206b0f1 | ||
|
|
e961e11487 | ||
|
|
f140d7979e | ||
|
|
afa27e4173 | ||
|
|
a9ac86ba3d | ||
|
|
f3d771641d | ||
|
|
f6dc11650d | ||
|
|
dce28b2dac | ||
|
|
8345eae28c | ||
|
|
e8219e6b6a | ||
|
|
9cc60ab63d | ||
|
|
3828211446 | ||
|
|
36aa57e89c | ||
|
|
22030e1153 | ||
|
|
73b042b41e | ||
|
|
f52607f722 | ||
|
|
f00ed17783 | ||
|
|
5840d2b61b | ||
|
|
17d3e659c1 | ||
|
|
c129118496 | ||
|
|
05c0874f32 | ||
|
|
2e5442d386 | ||
|
|
f9ae0cfdb3 | ||
|
|
7ad90de184 | ||
|
|
4383ddfe65 | ||
|
|
2a0ce72792 | ||
|
|
45373ad680 | ||
|
|
5ced8a5a9e | ||
|
|
bddc9dc6aa | ||
|
|
7c3de9f30a | ||
|
|
2adcf2d35d | ||
|
|
9a4ec5a82a | ||
|
|
7500ea83a0 | ||
|
|
6fd3294fba | ||
|
|
bfa163f3c2 | ||
|
|
d8826a9db3 | ||
|
|
b9e3de2d50 | ||
|
|
e163598ee6 | ||
|
|
2c059e1a6e | ||
|
|
6f21059ff8 | ||
|
|
523ced2f9a | ||
|
|
58a5a17464 | ||
|
|
cb0a6f5460 | ||
|
|
b919d3e411 | ||
|
|
02f30a81dd | ||
|
|
e57bcba47d | ||
|
|
aae61f3b2e | ||
|
|
d88bb43d9c | ||
|
|
71f9058723 | ||
|
|
0564ded492 | ||
|
|
ff48d3a186 | ||
|
|
4fa3225cba | ||
|
|
ee24943c72 | ||
|
|
31e4c60db8 | ||
|
|
ab536e2279 | ||
|
|
3d47ff469f | ||
|
|
3b4a3828ba | ||
|
|
c6d000972e | ||
|
|
51ee4d3d1d | ||
|
|
044d9c0746 | ||
|
|
593db4cd8d | ||
|
|
f90ad8caeb | ||
|
|
3401414430 | ||
|
|
50216647ca | ||
|
|
98063c8bf7 | ||
|
|
9747cc4ddc | ||
|
|
95cd24a124 | ||
|
|
6452f6a97a | ||
|
|
7e23597351 | ||
|
|
437c0880e8 | ||
|
|
e2db1a086d | ||
|
|
9f8db42584 | ||
|
|
376e31bfca | ||
|
|
3735dd0e6a | ||
|
|
199b9962f0 | ||
|
|
4d4362b250 |
19
.github/workflows/swift.yml
vendored
Normal file
19
.github/workflows/swift.yml
vendored
Normal file
@ -0,0 +1,19 @@
|
||||
name: Swift
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ "master", "development" ]
|
||||
pull_request:
|
||||
branches: [ "master", "development" ]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
|
||||
runs-on: macos-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Build
|
||||
run: swift build -v
|
||||
- name: Run tests
|
||||
run: swift test -v
|
||||
6
.gitignore
vendored
6
.gitignore
vendored
@ -46,3 +46,9 @@ DerivedData
|
||||
*.xcuserstate
|
||||
|
||||
Socket.IO-Test-Server/node_modules/*
|
||||
|
||||
.idea/
|
||||
docs/docsets/
|
||||
docs/undocumented.json
|
||||
|
||||
.swiftpm
|
||||
|
||||
7
.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata
generated
Normal file
7
.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata
generated
Normal file
@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Workspace
|
||||
version = "1.0">
|
||||
<FileRef
|
||||
location = "self:">
|
||||
</FileRef>
|
||||
</Workspace>
|
||||
13
.travis.yml
13
.travis.yml
@ -1,13 +0,0 @@
|
||||
language: objective-c
|
||||
xcode_project: Socket.IO-Client-Swift.xcodeproj # path to your xcodeproj folder
|
||||
xcode_scheme: SocketIO-iOS
|
||||
osx_image: xcode7.3
|
||||
before_install:
|
||||
- cd Socket.IO-Test-Server/
|
||||
- npm install
|
||||
- cd ..
|
||||
install: node Socket.IO-Test-Server/main.js &
|
||||
script: xctool -project Socket.IO-Client-Swift.xcodeproj -scheme SocketIO-Mac build test -parallelize
|
||||
cache:
|
||||
directories:
|
||||
- Socket.IO-Test-Server/node_modules
|
||||
104
CHANGELOG.md
Normal file
104
CHANGELOG.md
Normal file
@ -0,0 +1,104 @@
|
||||
# v16.1.0
|
||||
|
||||
- Remove support for iOS 11.
|
||||
- Update to Starscream 4.0.6
|
||||
|
||||
# v16.0.0
|
||||
|
||||
- Removed Objective-C support. It's time for you to embrace Swift.
|
||||
- Socket.io 3 support.
|
||||
|
||||
# v15.3.0
|
||||
|
||||
- Add `==` operators for `SocketAckStatus` and `String`
|
||||
|
||||
# v15.2.0
|
||||
|
||||
- Small fixes.
|
||||
|
||||
# v15.1.0
|
||||
|
||||
- Add ability to enable websockets SOCKS proxy.
|
||||
- Fix emit completion callback not firing on websockets [#1178](https://github.com/socketio/socket.io-client-swift/issues/1178)
|
||||
|
||||
# v15.0.0
|
||||
|
||||
- Swift 5
|
||||
|
||||
# v14.0.0
|
||||
|
||||
- Minimum version of the client is now Swift 4.2.
|
||||
- Add exponential backoff for reconnects, with `reconnectWaitMax` and `randomizationFactor` options [#1149](https://github.com/socketio/socket.io-client-swift/pull/1149)
|
||||
- `statusChange` event's data format adds a second value, the raw value of the status. This is for use in Objective-C. [#1147](https://github.com/socketio/socket.io-client-swift/issues/1147)
|
||||
|
||||
# v13.4.0
|
||||
|
||||
- Add emits with write completion handlers. [#1096](https://github.com/socketio/socket.io-client-swift/issues/1096)
|
||||
- Add ability to listen for when a websocket upgrade happens
|
||||
|
||||
# v13.3.1
|
||||
|
||||
- Fixes various bugs. [#857](https://github.com/socketio/socket.io-client-swift/issues/857), [#1078](https://github.com/socketio/socket.io-client-swift/issues/1078)
|
||||
|
||||
# v13.3.0
|
||||
|
||||
- Copy cookies from polling to WebSockets ([#1057](https://github.com/socketio/socket.io-client-swift/issues/1057), [#1058](https://github.com/socketio/socket.io-client-swift/issues/1058))
|
||||
|
||||
# v13.2.1
|
||||
|
||||
- Fix packets getting lost when WebSocket upgrade fails. [#1033](https://github.com/socketio/socket.io-client-swift/issues/1033)
|
||||
- Fix bad unit tests. [#794](https://github.com/socketio/socket.io-client-swift/issues/794)
|
||||
|
||||
# v13.2.0
|
||||
|
||||
- Add ability to bypass Data inspection in emits. [#992]((https://github.com/socketio/socket.io-client-swift/issues/992))
|
||||
- Allow `SocketEngine` to be subclassed
|
||||
|
||||
# v13.1.3
|
||||
|
||||
- Fix setting reconnectAttempts [#989]((https://github.com/socketio/socket.io-client-swift/issues/989))
|
||||
|
||||
|
||||
# v13.1.2
|
||||
|
||||
- Fix [#950](https://github.com/socketio/socket.io-client-swift/issues/950)
|
||||
- Conforming to `SocketEngineWebsocket` no longer requires conforming to `WebsocketDelegate`
|
||||
|
||||
|
||||
# v13.1.1
|
||||
|
||||
- Fix [#923](https://github.com/socketio/socket.io-client-swift/issues/923)
|
||||
- Fix [#894](https://github.com/socketio/socket.io-client-swift/issues/894)
|
||||
|
||||
# v13.1.0
|
||||
|
||||
- Allow setting `SocketEngineSpec.extraHeaders` after init.
|
||||
- Deprecate `SocketEngineSpec.websocket` in favor of just using the `SocketEngineSpec.polling` property.
|
||||
- Enable bitcode for most platforms.
|
||||
- Fix [#882](https://github.com/socketio/socket.io-client-swift/issues/882). This adds a new method
|
||||
`SocketManger.removeSocket(_:)` that should be called if when you no longer wish to use a socket again.
|
||||
This will cause the engine to no longer keep a strong reference to the socket and no longer track it.
|
||||
|
||||
# v13.0.1
|
||||
|
||||
- Fix not setting handleQueue on `SocketManager`
|
||||
|
||||
# v13.0.0
|
||||
|
||||
Checkout out the migration guide in Usage Docs for a more detailed guide on how to migrate to this version.
|
||||
|
||||
What's new:
|
||||
---
|
||||
|
||||
- Adds a new `SocketManager` class that multiplexes multiple namespaces through a single engine.
|
||||
- Adds `.sentPing` and `.gotPong` client events for tracking ping/pongs.
|
||||
- watchOS support.
|
||||
|
||||
Important API changes
|
||||
---
|
||||
|
||||
- Many properties that were previously on `SocketIOClient` have been moved to the `SocketManager`.
|
||||
- `SocketIOClientOption.nsp` has been removed. Use `SocketManager.socket(forNamespace:)` to create/get a socket attached to a specific namespace.
|
||||
- Adds `.sentPing` and `.gotPong` client events for tracking ping/pongs.
|
||||
- Makes the framework a single target.
|
||||
- Updates Starscream to 3.0
|
||||
1
Cartfile.resolved
Normal file
1
Cartfile.resolved
Normal file
@ -0,0 +1 @@
|
||||
github "daltoniam/Starscream" "4.0.8"
|
||||
16
Package.resolved
Normal file
16
Package.resolved
Normal file
@ -0,0 +1,16 @@
|
||||
{
|
||||
"object": {
|
||||
"pins": [
|
||||
{
|
||||
"package": "Starscream",
|
||||
"repositoryURL": "https://github.com/daltoniam/Starscream",
|
||||
"state": {
|
||||
"branch": null,
|
||||
"revision": "c6bfd1af48efcc9a9ad203665db12375ba6b145a",
|
||||
"version": "4.0.8"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"version": 1
|
||||
}
|
||||
@ -1,5 +1,17 @@
|
||||
// swift-tools-version:5.4
|
||||
|
||||
import PackageDescription
|
||||
|
||||
let package = Package(
|
||||
name: "SocketIOClientSwift"
|
||||
name: "SocketIO",
|
||||
products: [
|
||||
.library(name: "SocketIO", targets: ["SocketIO"])
|
||||
],
|
||||
dependencies: [
|
||||
.package(url: "https://github.com/daltoniam/Starscream", .upToNextMajor(from: "4.0.8")),
|
||||
],
|
||||
targets: [
|
||||
.target(name: "SocketIO", dependencies: ["Starscream"]),
|
||||
.testTarget(name: "TestSocketIO", dependencies: ["SocketIO"]),
|
||||
]
|
||||
)
|
||||
|
||||
184
README.md
184
README.md
@ -1,108 +1,95 @@
|
||||
[](https://travis-ci.org/socketio/socket.io-client-swift)
|
||||
|
||||
#Socket.IO-Client-Swift
|
||||
# Socket.IO-Client-Swift
|
||||
Socket.IO-client for iOS/OS X.
|
||||
|
||||
##Example
|
||||
## Example
|
||||
```swift
|
||||
let socket = SocketIOClient(socketURL: NSURL(string: "http://localhost:8080")!, options: [.Log(true), .ForcePolling(true)])
|
||||
import SocketIO
|
||||
|
||||
socket.on("connect") {data, ack in
|
||||
let manager = SocketManager(socketURL: URL(string: "http://localhost:8080")!, config: [.log(true), .compress])
|
||||
let socket = manager.defaultSocket
|
||||
|
||||
socket.on(clientEvent: .connect) {data, ack in
|
||||
print("socket connected")
|
||||
}
|
||||
|
||||
socket.on("currentAmount") {data, ack in
|
||||
if let cur = data[0] as? Double {
|
||||
socket.emitWithAck("canUpdate", cur)(timeoutAfter: 0) {data in
|
||||
socket.emit("update", ["amount": cur + 2.50])
|
||||
guard let cur = data[0] as? Double else { return }
|
||||
|
||||
socket.emitWithAck("canUpdate", cur).timingOut(after: 0) {data in
|
||||
if data.first as? String ?? "passed" == SocketAckStatus.noAck {
|
||||
// Handle ack timeout
|
||||
}
|
||||
|
||||
ack.with("Got your currentAmount", "dude")
|
||||
socket.emit("update", ["amount": cur + 2.50])
|
||||
}
|
||||
|
||||
ack.with("Got your currentAmount", "dude")
|
||||
}
|
||||
|
||||
socket.connect()
|
||||
```
|
||||
|
||||
##Objective-C Example
|
||||
```objective-c
|
||||
NSURL* url = [[NSURL alloc] initWithString:@"http://localhost:8080"];
|
||||
SocketIOClient* socket = [[SocketIOClient alloc] initWithSocketURL:url options:@{@"log": @YES, @"forcePolling": @YES}];
|
||||
|
||||
[socket on:@"connect" callback:^(NSArray* data, SocketAckEmitter* ack) {
|
||||
NSLog(@"socket connected");
|
||||
}];
|
||||
|
||||
[socket on:@"currentAmount" callback:^(NSArray* data, SocketAckEmitter* ack) {
|
||||
double cur = [[data objectAtIndex:0] floatValue];
|
||||
|
||||
[socket emitWithAck:@"canUpdate" withItems:@[@(cur)]](0, ^(NSArray* data) {
|
||||
[socket emit:@"update" withItems:@[@{@"amount": @(cur + 2.50)}]];
|
||||
});
|
||||
|
||||
[ack with:@[@"Got your currentAmount, ", @"dude"]];
|
||||
}];
|
||||
|
||||
[socket connect];
|
||||
|
||||
```
|
||||
|
||||
##Features
|
||||
- Supports socket.io 1.0+
|
||||
- Supports binary
|
||||
## Features
|
||||
- Supports Socket.IO server 2.0+/3.0+/4.0+ (see the [compatibility table](https://nuclearace.github.io/Socket.IO-Client-Swift/Compatibility.html))
|
||||
- Supports Binary
|
||||
- Supports Polling and WebSockets
|
||||
- Supports TLS/SSL
|
||||
- Can be used from Objective-C
|
||||
|
||||
##Installation
|
||||
Requires Swift 2.2/Xcode 7.3
|
||||
## FAQS
|
||||
Checkout the [FAQs](https://nuclearace.github.io/Socket.IO-Client-Swift/faq.html) for commonly asked questions.
|
||||
|
||||
If you need Swift 2.1/Xcode 7.2 use v5.5.0 (Pre-Swift 2.2 support is no longer maintained)
|
||||
|
||||
If you need Swift 1.2/Xcode 6.3/4 use v2.4.5 (Pre-Swift 2 support is no longer maintained)
|
||||
Checkout the [12to13](https://nuclearace.github.io/Socket.IO-Client-Swift/12to13.html) guide for migrating to v13+ from v12 below.
|
||||
|
||||
If you need Swift 1.1/Xcode 6.2 use v1.5.2. (Pre-Swift 1.2 support is no longer maintained)
|
||||
Checkout the [15to16](https://nuclearace.github.io/Socket.IO-Client-Swift/15to16.html) guide for migrating to v16+ from v15.
|
||||
|
||||
Manually (iOS 7+)
|
||||
-----------------
|
||||
1. Copy the Source folder into your Xcode project. (Make sure you add the files to your target(s))
|
||||
2. If you plan on using this from Objective-C, read [this](https://developer.apple.com/library/ios/documentation/Swift/Conceptual/BuildingCocoaApps/MixandMatch.html) on exposing Swift code to Objective-C.
|
||||
## Installation
|
||||
Requires Swift 4/5 and Xcode 10.x
|
||||
|
||||
Swift Package Manager
|
||||
---------------------
|
||||
### Swift Package Manager
|
||||
Add the project as a dependency to your Package.swift:
|
||||
```swift
|
||||
// swift-tools-version:4.2
|
||||
|
||||
import PackageDescription
|
||||
|
||||
let package = Package(
|
||||
name: "YourSocketIOProject",
|
||||
name: "socket.io-test",
|
||||
products: [
|
||||
.executable(name: "socket.io-test", targets: ["YourTargetName"])
|
||||
],
|
||||
dependencies: [
|
||||
.Package(url: "https://github.com/socketio/socket.io-client-swift", majorVersion: 6)
|
||||
.package(url: "https://github.com/socketio/socket.io-client-swift", .upToNextMinor(from: "16.1.1"))
|
||||
],
|
||||
targets: [
|
||||
.target(name: "YourTargetName", dependencies: ["SocketIO"], path: "./Path/To/Your/Sources")
|
||||
]
|
||||
)
|
||||
```
|
||||
|
||||
Then import `import SocketIOClientSwift`.
|
||||
Then import `import SocketIO`.
|
||||
|
||||
Carthage
|
||||
-----------------
|
||||
### Carthage
|
||||
Add this line to your `Cartfile`:
|
||||
```
|
||||
github "socketio/socket.io-client-swift" ~> 6.1.1 # Or latest version
|
||||
github "socketio/socket.io-client-swift" ~> 16.1.1
|
||||
```
|
||||
|
||||
Run `carthage update --platform ios,macosx`.
|
||||
|
||||
CocoaPods 0.36.0 or later (iOS 8+)
|
||||
------------------
|
||||
Add the `Starscream` and `SocketIO` frameworks to your projects and follow the usual Carthage process.
|
||||
|
||||
### CocoaPods 1.0.0 or later
|
||||
Create `Podfile` and add `pod 'Socket.IO-Client-Swift'`:
|
||||
|
||||
```ruby
|
||||
source 'https://github.com/CocoaPods/Specs.git'
|
||||
platform :ios, '8.0'
|
||||
use_frameworks!
|
||||
|
||||
pod 'Socket.IO-Client-Swift', '~> 6.1.1' # Or latest version
|
||||
target 'YourApp' do
|
||||
pod 'Socket.IO-Client-Swift', '~> 16.1.1'
|
||||
end
|
||||
```
|
||||
|
||||
Install pods:
|
||||
@ -115,88 +102,27 @@ Import the module:
|
||||
|
||||
Swift:
|
||||
```swift
|
||||
import SocketIOClientSwift
|
||||
import SocketIO
|
||||
```
|
||||
|
||||
Objective-C:
|
||||
|
||||
```Objective-C
|
||||
#import <SocketIOClientSwift/SocketIOClientSwift-Swift.h>
|
||||
@import SocketIO;
|
||||
```
|
||||
|
||||
CocoaSeeds
|
||||
-----------------
|
||||
|
||||
Add this line to your `Seedfile`:
|
||||
# [Docs](https://nuclearace.github.io/Socket.IO-Client-Swift/index.html)
|
||||
|
||||
```
|
||||
github "socketio/socket.io-client-swift", "v6.1.1", :files => "Source/*.swift" # Or latest version
|
||||
```
|
||||
- [Client](https://nuclearace.github.io/Socket.IO-Client-Swift/Classes/SocketIOClient.html)
|
||||
- [Manager](https://nuclearace.github.io/Socket.IO-Client-Swift/Classes/SocketManager.html)
|
||||
- [Engine](https://nuclearace.github.io/Socket.IO-Client-Swift/Classes/SocketEngine.html)
|
||||
- [Options](https://nuclearace.github.io/Socket.IO-Client-Swift/Enums/SocketIOClientOption.html)
|
||||
|
||||
Run `seed install`.
|
||||
|
||||
|
||||
##API
|
||||
Constructors
|
||||
-----------
|
||||
`init(var socketURL: NSURL, options: Set<SocketIOClientOption> = [])` - Creates a new SocketIOClient. options is a Set of SocketIOClientOption. If your socket.io server is secure, you need to specify `https` in your socketURL.
|
||||
|
||||
`convenience init(socketURL: NSURL, options: NSDictionary?)` - Same as above, but meant for Objective-C. See Options on how convert between SocketIOClientOptions and dictionary keys.
|
||||
|
||||
Options
|
||||
-------
|
||||
All options are a case of SocketIOClientOption. To get the Objective-C Option, convert the name to lowerCamelCase.
|
||||
|
||||
```swift
|
||||
case ConnectParams([String: AnyObject]) // Dictionary whose contents will be passed with the connection.
|
||||
case Cookies([NSHTTPCookie]) // An array of NSHTTPCookies. Passed during the handshake. Default is nil.
|
||||
case DoubleEncodeUTF8(Bool) // Whether or not to double encode utf8. If using the node based server this should be true. Default is true.
|
||||
case ExtraHeaders([String: String]) // Adds custom headers to the initial request. Default is nil.
|
||||
case ForcePolling(Bool) // `true` forces the client to use xhr-polling. Default is `false`
|
||||
case ForceNew(Bool) // Will a create a new engine for each connect. Useful if you find a bug in the engine related to reconnects
|
||||
case ForceWebsockets(Bool) // `true` forces the client to use WebSockets. Default is `false`
|
||||
case HandleQueue(dispatch_queue_t) // The dispatch queue that handlers are run on. Default is the main queue.
|
||||
case Log(Bool) // If `true` socket will log debug messages. Default is false.
|
||||
case Logger(SocketLogger) // Custom logger that conforms to SocketLogger. Will use the default logging otherwise.
|
||||
case Nsp(String) // The namespace to connect to. Must begin with /. Default is `/`
|
||||
case Path(String) // If the server uses a custom path. ex: `"/swift/"`. Default is `""`
|
||||
case Reconnects(Bool) // Whether to reconnect on server lose. Default is `true`
|
||||
case ReconnectAttempts(Int) // How many times to reconnect. Default is `-1` (infinite tries)
|
||||
case ReconnectWait(Int) // Amount of time to wait between reconnects. Default is `10`
|
||||
case SessionDelegate(NSURLSessionDelegate) // Sets an NSURLSessionDelegate for the underlying engine. Useful if you need to handle self-signed certs. Default is nil.
|
||||
case Secure(Bool) // If the connection should use TLS. Default is false.
|
||||
case SelfSigned(Bool) // Sets WebSocket.selfSignedSSL (Don't do this, iOS will yell at you)
|
||||
case VoipEnabled(Bool) // Only use this option if you're using the client with VoIP services. Changes the way the WebSocket is created. Default is false
|
||||
```
|
||||
Methods
|
||||
-------
|
||||
1. `on(event: String, callback: NormalCallback) -> NSUUID` - Adds a handler for an event. Items are passed by an array. `ack` can be used to send an ack when one is requested. See example. Returns a unique id for the handler.
|
||||
2. `once(event: String, callback: NormalCallback) -> NSUUID` - Adds a handler that will only be executed once. Returns a unique id for the handler.
|
||||
3. `onAny(callback:((event: String, items: AnyObject?)) -> Void)` - Adds a handler for all events. It will be called on any received event.
|
||||
4. `emit(event: String, _ items: AnyObject...)` - Sends a message. Can send multiple items.
|
||||
5. `emit(event: String, withItems items: [AnyObject])` - `emit` for Objective-C
|
||||
6. `emitWithAck(event: String, _ items: AnyObject...) -> (timeoutAfter: UInt64, callback: (NSArray?) -> Void) -> Void` - Sends a message that requests an acknowledgement from the server. Returns a function which you can use to add a handler. See example. Note: The message is not sent until you call the returned function.
|
||||
7. `emitWithAck(event: String, withItems items: [AnyObject]) -> (UInt64, (NSArray?) -> Void) -> Void` - `emitWithAck` for Objective-C. Note: The message is not sent until you call the returned function.
|
||||
8. `connect()` - Establishes a connection to the server. A "connect" event is fired upon successful connection.
|
||||
9. `connect(timeoutAfter timeoutAfter: Int, withTimeoutHandler handler: (() -> Void)?)` - Connect to the server. If it isn't connected after timeoutAfter seconds, the handler is called.
|
||||
10. `disconnect()` - Closes the socket. Reopening a disconnected socket is not fully tested.
|
||||
11. `reconnect()` - Causes the client to reconnect to the server.
|
||||
12. `joinNamespace(namespace: String)` - Causes the client to join namespace. Shouldn't need to be called unless you change namespaces manually.
|
||||
13. `leaveNamespace()` - Causes the client to leave the nsp and go back to /
|
||||
14. `off(event: String)` - Removes all event handlers for event.
|
||||
15. `off(id id: NSUUID)` - Removes the event that corresponds to id.
|
||||
16. `removeAllHandlers()` - Removes all handlers.
|
||||
|
||||
Client Events
|
||||
------
|
||||
1. `connect` - Emitted when on a successful connection.
|
||||
2. `disconnect` - Emitted when the connection is closed.
|
||||
3. `error` - Emitted on an error.
|
||||
4. `reconnect` - Emitted when the connection is starting to reconnect.
|
||||
5. `reconnectAttempt` - Emitted when attempting to reconnect.
|
||||
|
||||
##Detailed Example
|
||||
## Detailed Example
|
||||
A more detailed example can be found [here](https://github.com/nuclearace/socket.io-client-swift-example)
|
||||
|
||||
##License
|
||||
An example using the Swift Package Manager can be found [here](https://github.com/nuclearace/socket.io-client-swift-spm-example)
|
||||
|
||||
## License
|
||||
MIT
|
||||
|
||||
@ -1,21 +1,31 @@
|
||||
Pod::Spec.new do |s|
|
||||
s.name = "Socket.IO-Client-Swift"
|
||||
s.module_name = "SocketIOClientSwift"
|
||||
s.version = "6.1.1"
|
||||
s.module_name = "SocketIO"
|
||||
s.version = "16.1.1"
|
||||
s.summary = "Socket.IO-client for iOS and OS X"
|
||||
s.description = <<-DESC
|
||||
Socket.IO-client for iOS and OS X.
|
||||
Supports ws/wss/polling connections and binary.
|
||||
For socket.io 1.0+ and Swift.
|
||||
For socket.io 3.0+ and Swift.
|
||||
DESC
|
||||
s.homepage = "https://github.com/socketio/socket.io-client-swift"
|
||||
s.license = { :type => 'MIT' }
|
||||
s.author = { "Erik" => "nuclear.ace@gmail.com" }
|
||||
s.ios.deployment_target = '8.0'
|
||||
s.osx.deployment_target = '10.10'
|
||||
s.tvos.deployment_target = '9.0'
|
||||
s.source = { :git => "https://github.com/socketio/socket.io-client-swift.git", :tag => 'v6.1.1' }
|
||||
s.source_files = "Source/**/*.swift"
|
||||
s.ios.deployment_target = '12.0'
|
||||
s.osx.deployment_target = '10.13'
|
||||
s.tvos.deployment_target = '12.0'
|
||||
s.watchos.deployment_target = '5.0'
|
||||
s.requires_arc = true
|
||||
# s.dependency 'Starscream', '~> 0.9' # currently this repo includes Starscream swift files
|
||||
s.source = {
|
||||
:git => "https://github.com/socketio/socket.io-client-swift.git",
|
||||
:tag => 'v16.1.1',
|
||||
:submodules => true
|
||||
}
|
||||
|
||||
s.swift_version = "5"
|
||||
s.pod_target_xcconfig = {
|
||||
'SWIFT_VERSION' => '5.4'
|
||||
}
|
||||
s.source_files = "Source/SocketIO/**/*.swift", "Source/SocketIO/*.swift"
|
||||
s.dependency "Starscream", "~> 4.0.8"
|
||||
end
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -1,114 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "0720"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
buildImplicitDependencies = "YES">
|
||||
<BuildActionEntries>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
buildForRunning = "YES"
|
||||
buildForProfiling = "YES"
|
||||
buildForArchiving = "YES"
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "572EF2181B51F16C00EEBB58"
|
||||
BuildableName = "SocketIOClientSwift.framework"
|
||||
BlueprintName = "SocketIO-iOS"
|
||||
ReferencedContainer = "container:Socket.IO-Client-Swift.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
buildForRunning = "NO"
|
||||
buildForProfiling = "NO"
|
||||
buildForArchiving = "NO"
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "572EF2231B51F16C00EEBB58"
|
||||
BuildableName = "SocketIO-iOSTests.xctest"
|
||||
BlueprintName = "SocketIO-iOSTests"
|
||||
ReferencedContainer = "container:Socket.IO-Client-Swift.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
</BuildActionEntries>
|
||||
</BuildAction>
|
||||
<TestAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
codeCoverageEnabled = "YES">
|
||||
<Testables>
|
||||
<TestableReference
|
||||
skipped = "NO">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "572EF2231B51F16C00EEBB58"
|
||||
BuildableName = "SocketIO-iOSTests.xctest"
|
||||
BlueprintName = "SocketIO-iOSTests"
|
||||
ReferencedContainer = "container:Socket.IO-Client-Swift.xcodeproj">
|
||||
</BuildableReference>
|
||||
</TestableReference>
|
||||
</Testables>
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "572EF2181B51F16C00EEBB58"
|
||||
BuildableName = "SocketIOClientSwift.framework"
|
||||
BlueprintName = "SocketIO-iOS"
|
||||
ReferencedContainer = "container:Socket.IO-Client-Swift.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
<AdditionalOptions>
|
||||
</AdditionalOptions>
|
||||
</TestAction>
|
||||
<LaunchAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
launchStyle = "0"
|
||||
useCustomWorkingDirectory = "NO"
|
||||
ignoresPersistentStateOnLaunch = "NO"
|
||||
debugDocumentVersioning = "YES"
|
||||
debugServiceExtension = "internal"
|
||||
allowLocationSimulation = "YES">
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "572EF2181B51F16C00EEBB58"
|
||||
BuildableName = "SocketIOClientSwift.framework"
|
||||
BlueprintName = "SocketIO-iOS"
|
||||
ReferencedContainer = "container:Socket.IO-Client-Swift.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
<AdditionalOptions>
|
||||
</AdditionalOptions>
|
||||
</LaunchAction>
|
||||
<ProfileAction
|
||||
buildConfiguration = "Release"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
savedToolIdentifier = ""
|
||||
useCustomWorkingDirectory = "NO"
|
||||
debugDocumentVersioning = "YES">
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "572EF2181B51F16C00EEBB58"
|
||||
BuildableName = "SocketIOClientSwift.framework"
|
||||
BlueprintName = "SocketIO-iOS"
|
||||
ReferencedContainer = "container:Socket.IO-Client-Swift.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
</ProfileAction>
|
||||
<AnalyzeAction
|
||||
buildConfiguration = "Debug">
|
||||
</AnalyzeAction>
|
||||
<ArchiveAction
|
||||
buildConfiguration = "Release"
|
||||
revealArchiveInOrganizer = "YES">
|
||||
</ArchiveAction>
|
||||
</Scheme>
|
||||
@ -1,113 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "0720"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
buildImplicitDependencies = "YES">
|
||||
<BuildActionEntries>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
buildForRunning = "YES"
|
||||
buildForProfiling = "YES"
|
||||
buildForArchiving = "YES"
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "576349FA1BD9B46A00E19CD7"
|
||||
BuildableName = "SocketIO.framework"
|
||||
BlueprintName = "SocketIO-tvOS"
|
||||
ReferencedContainer = "container:Socket.IO-Client-Swift.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
buildForRunning = "NO"
|
||||
buildForProfiling = "NO"
|
||||
buildForArchiving = "NO"
|
||||
buildForAnalyzing = "NO">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "57634A181BD9B46D00E19CD7"
|
||||
BuildableName = "SocketIO-tvOSTests.xctest"
|
||||
BlueprintName = "SocketIO-tvOSTests"
|
||||
ReferencedContainer = "container:Socket.IO-Client-Swift.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
</BuildActionEntries>
|
||||
</BuildAction>
|
||||
<TestAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||
<Testables>
|
||||
<TestableReference
|
||||
skipped = "NO">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "57634A181BD9B46D00E19CD7"
|
||||
BuildableName = "SocketIO-tvOSTests.xctest"
|
||||
BlueprintName = "SocketIO-tvOSTests"
|
||||
ReferencedContainer = "container:Socket.IO-Client-Swift.xcodeproj">
|
||||
</BuildableReference>
|
||||
</TestableReference>
|
||||
</Testables>
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "576349FA1BD9B46A00E19CD7"
|
||||
BuildableName = "SocketIO.framework"
|
||||
BlueprintName = "SocketIO-tvOS"
|
||||
ReferencedContainer = "container:Socket.IO-Client-Swift.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
<AdditionalOptions>
|
||||
</AdditionalOptions>
|
||||
</TestAction>
|
||||
<LaunchAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
launchStyle = "0"
|
||||
useCustomWorkingDirectory = "NO"
|
||||
ignoresPersistentStateOnLaunch = "NO"
|
||||
debugDocumentVersioning = "YES"
|
||||
debugServiceExtension = "internal"
|
||||
allowLocationSimulation = "YES">
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "576349FA1BD9B46A00E19CD7"
|
||||
BuildableName = "SocketIO.framework"
|
||||
BlueprintName = "SocketIO-tvOS"
|
||||
ReferencedContainer = "container:Socket.IO-Client-Swift.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
<AdditionalOptions>
|
||||
</AdditionalOptions>
|
||||
</LaunchAction>
|
||||
<ProfileAction
|
||||
buildConfiguration = "Release"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
savedToolIdentifier = ""
|
||||
useCustomWorkingDirectory = "NO"
|
||||
debugDocumentVersioning = "YES">
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "576349FA1BD9B46A00E19CD7"
|
||||
BuildableName = "SocketIO.framework"
|
||||
BlueprintName = "SocketIO-tvOS"
|
||||
ReferencedContainer = "container:Socket.IO-Client-Swift.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
</ProfileAction>
|
||||
<AnalyzeAction
|
||||
buildConfiguration = "Debug">
|
||||
</AnalyzeAction>
|
||||
<ArchiveAction
|
||||
buildConfiguration = "Release"
|
||||
revealArchiveInOrganizer = "YES">
|
||||
</ArchiveAction>
|
||||
</Scheme>
|
||||
@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "0720"
|
||||
LastUpgradeVersion = "1020"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
@ -15,8 +15,8 @@
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "572EF2371B51F18A00EEBB58"
|
||||
BuildableName = "SocketIOClientSwift.framework"
|
||||
BlueprintName = "SocketIO-Mac"
|
||||
BuildableName = "SocketIO.framework"
|
||||
BlueprintName = "SocketIO"
|
||||
ReferencedContainer = "container:Socket.IO-Client-Swift.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
@ -29,8 +29,8 @@
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "572EF2411B51F18A00EEBB58"
|
||||
BuildableName = "SocketIO-MacTests.xctest"
|
||||
BlueprintName = "SocketIO-MacTests"
|
||||
BuildableName = "SocketIO-Tests.xctest"
|
||||
BlueprintName = "SocketIO-Tests"
|
||||
ReferencedContainer = "container:Socket.IO-Client-Swift.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
@ -47,8 +47,8 @@
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "572EF2411B51F18A00EEBB58"
|
||||
BuildableName = "SocketIO-MacTests.xctest"
|
||||
BlueprintName = "SocketIO-MacTests"
|
||||
BuildableName = "SocketIO-Tests.xctest"
|
||||
BlueprintName = "SocketIO-Tests"
|
||||
ReferencedContainer = "container:Socket.IO-Client-Swift.xcodeproj">
|
||||
</BuildableReference>
|
||||
</TestableReference>
|
||||
@ -57,8 +57,8 @@
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "572EF2371B51F18A00EEBB58"
|
||||
BuildableName = "SocketIOClientSwift.framework"
|
||||
BlueprintName = "SocketIO-Mac"
|
||||
BuildableName = "SocketIO.framework"
|
||||
BlueprintName = "SocketIO"
|
||||
ReferencedContainer = "container:Socket.IO-Client-Swift.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
@ -79,8 +79,8 @@
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "572EF2371B51F18A00EEBB58"
|
||||
BuildableName = "SocketIOClientSwift.framework"
|
||||
BlueprintName = "SocketIO-Mac"
|
||||
BuildableName = "SocketIO.framework"
|
||||
BlueprintName = "SocketIO"
|
||||
ReferencedContainer = "container:Socket.IO-Client-Swift.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
@ -97,8 +97,8 @@
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "572EF2371B51F18A00EEBB58"
|
||||
BuildableName = "SocketIOClientSwift.framework"
|
||||
BlueprintName = "SocketIO-Mac"
|
||||
BuildableName = "SocketIO.framework"
|
||||
BlueprintName = "SocketIO"
|
||||
ReferencedContainer = "container:Socket.IO-Client-Swift.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
@ -1,95 +0,0 @@
|
||||
var assert = require("assert")
|
||||
|
||||
module.exports = {
|
||||
basicTest: {
|
||||
assert: function(inputData) {
|
||||
|
||||
},
|
||||
returnData: []
|
||||
},
|
||||
testNull: {
|
||||
assert: function(inputData) {
|
||||
assert(!inputData)
|
||||
},
|
||||
returnData: [null]
|
||||
},
|
||||
testBinary: {
|
||||
assert: function(inputData) {
|
||||
assert.equal(inputData.toString(), "gakgakgak2")
|
||||
},
|
||||
returnData: [new Buffer("gakgakgak2", "utf-8")]
|
||||
},
|
||||
testArray: {
|
||||
assert: function(inputData) {
|
||||
assert.equal(inputData.length, 2)
|
||||
assert.equal(inputData[0], "test1")
|
||||
assert.equal(inputData[1], "test2")
|
||||
},
|
||||
returnData: [["test3", "test4"]]
|
||||
},
|
||||
testString: {
|
||||
assert: function(inputData) {
|
||||
assert.equal(inputData, "marco")
|
||||
},
|
||||
returnData: ["polo"]
|
||||
},
|
||||
testBool: {
|
||||
assert: function(inputData) {
|
||||
assert(!inputData)
|
||||
},
|
||||
returnData: [true]
|
||||
},
|
||||
testInteger: {
|
||||
assert: function(inputData) {
|
||||
assert.equal(inputData, 10)
|
||||
},
|
||||
returnData: [20]
|
||||
},
|
||||
testDouble: {
|
||||
assert: function(inputData) {
|
||||
assert.equal(inputData, 1.1)
|
||||
},
|
||||
returnData: [1.2]
|
||||
},
|
||||
testJSON: {
|
||||
assert: function(inputData) {
|
||||
assert.equal(inputData.name, "test")
|
||||
assert.equal(inputData.nestedTest.test, "test")
|
||||
assert.equal(inputData.testArray.length, 1)
|
||||
},
|
||||
returnData: [{testString: "test", testNumber: 15, nestedTest: {test: "test"}, testArray: [1, 1]}]
|
||||
},
|
||||
testJSONWithBuffer: {
|
||||
assert: function(inputData) {
|
||||
assert.equal(inputData.name, "test")
|
||||
assert.equal(inputData.nestedTest.test, "test")
|
||||
assert.equal(inputData.testArray.length, 1)
|
||||
},
|
||||
returnData: [{testString: "test", testNumber: 15, nestedTest: {test: "test"}, testArray: [new Buffer("gakgakgak2", "utf-8"), 1]}]
|
||||
},testUnicode: {
|
||||
assert: function(inputData) {
|
||||
assert.equal(inputData, "🚀")
|
||||
},
|
||||
returnData: ["🚄"]
|
||||
},testMultipleItems: {
|
||||
assert: function(array, object, number, string, bool) {
|
||||
assert.equal(array.length, 2)
|
||||
assert.equal(array[0], "test1")
|
||||
assert.equal(array[1], "test2")
|
||||
assert.equal(number, 15)
|
||||
assert.equal(string, "marco")
|
||||
assert.equal(bool, false)
|
||||
},
|
||||
returnData: [[1, 2], {test: "bob"}, 25, "polo", false]
|
||||
},testMultipleItemsWithBuffer: {
|
||||
assert: function(array, object, number, string, binary) {
|
||||
assert.equal(array.length, 2)
|
||||
assert.equal(array[0], "test1")
|
||||
assert.equal(array[1], "test2")
|
||||
assert.equal(number, 15)
|
||||
assert.equal(string, "marco")
|
||||
assert.equal(binary.toString(), "gakgakgak2")
|
||||
},
|
||||
returnData: [[1, 2], {test: "bob"}, 25, "polo", new Buffer("gakgakgak2")]
|
||||
}
|
||||
}
|
||||
@ -1,10 +0,0 @@
|
||||
function socketCallback(testKey, socket, testCase) {
|
||||
return function() {
|
||||
testCase.assert.apply(undefined , arguments)
|
||||
var emitArguments = testCase.returnData;
|
||||
var ack = arguments[arguments.length - 1]
|
||||
ack.apply(socket, emitArguments)
|
||||
}
|
||||
}
|
||||
|
||||
module.exports.socketCallback = socketCallback
|
||||
@ -1,20 +0,0 @@
|
||||
function socketCallback(testKey, socket, testCase) {
|
||||
return function() {
|
||||
testCase.assert.apply(undefined , arguments)
|
||||
|
||||
var emitArguments = addArrays([testKey + "EmitReturn"], testCase.returnData)
|
||||
socket.emit.apply(socket, emitArguments)
|
||||
}
|
||||
}
|
||||
|
||||
function addArrays(firstArray, secondArray) {
|
||||
var length = secondArray.length
|
||||
var i;
|
||||
for(i = 0; i < length; i++) {
|
||||
firstArray.push(secondArray[i])
|
||||
}
|
||||
|
||||
return firstArray;
|
||||
}
|
||||
|
||||
module.exports.socketCallback = socketCallback
|
||||
@ -1,15 +0,0 @@
|
||||
var app = require('http').createServer()
|
||||
var io = require('socket.io')(app);
|
||||
app.listen(6979)
|
||||
|
||||
|
||||
var acknowledgementsEvents = require("./acknowledgementEvents.js")
|
||||
var emitEvents = require("./emitEvents.js")
|
||||
var socketEventRegister = require("./socketEventRegister.js")
|
||||
|
||||
socketEventRegister.register(io, emitEvents.socketCallback, "Emit")
|
||||
socketEventRegister.register(io, acknowledgementsEvents.socketCallback, "Acknowledgement")
|
||||
|
||||
var nsp = io.of("/swift")
|
||||
socketEventRegister.register(nsp, emitEvents.socketCallback, "Emit")
|
||||
socketEventRegister.register(nsp, acknowledgementsEvents.socketCallback, "Acknowledgement")
|
||||
@ -1,14 +0,0 @@
|
||||
{
|
||||
"name": "socket.io-client-swift-test-server",
|
||||
"version": "0.0.1",
|
||||
"description": "A simple server to test aginst",
|
||||
"main": "main.js",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"author": "Lukas Schmidt",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"socket.io": "^1.3.6"
|
||||
}
|
||||
}
|
||||
@ -1,13 +0,0 @@
|
||||
var testCases = require("./TestCases.js")
|
||||
|
||||
function registerSocketForEvents(ioSocket, socketCallback, testKind) {
|
||||
ioSocket.on('connection', function(socket) {
|
||||
var testCase;
|
||||
for(testKey in testCases) {
|
||||
testCase = testCases[testKey]
|
||||
socket.on((testKey + testKind), socketCallback(testKey, socket, testCase))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
module.exports.register = registerSocketForEvents
|
||||
@ -1,24 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>en</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>$(EXECUTABLE_NAME)</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>$(PRODUCT_NAME)</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>BNDL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.0</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1</string>
|
||||
</dict>
|
||||
</plist>
|
||||
@ -1,26 +0,0 @@
|
||||
//
|
||||
// SocketAckManagerTest.swift
|
||||
// Socket.IO-Client-Swift
|
||||
//
|
||||
// Created by Lukas Schmidt on 04.09.15.
|
||||
//
|
||||
//
|
||||
|
||||
import XCTest
|
||||
@testable import SocketIOClientSwift
|
||||
|
||||
class SocketAckManagerTest: XCTestCase {
|
||||
var ackManager = SocketAckManager()
|
||||
|
||||
func testAddAcks() {
|
||||
let callbackExpection = self.expectationWithDescription("callbackExpection")
|
||||
let itemsArray = ["Hi", "ho"]
|
||||
func callback(items: [AnyObject]) {
|
||||
callbackExpection.fulfill()
|
||||
}
|
||||
ackManager.addAck(1, callback: callback)
|
||||
ackManager.executeAck(1, items: itemsArray)
|
||||
waitForExpectationsWithTimeout(3.0, handler: nil)
|
||||
|
||||
}
|
||||
}
|
||||
@ -1,148 +0,0 @@
|
||||
//
|
||||
// SocketBasicPacketTest.swift
|
||||
// Socket.IO-Client-Swift
|
||||
//
|
||||
// Created by Erik Little on 10/7/15.
|
||||
//
|
||||
//
|
||||
|
||||
import XCTest
|
||||
@testable import SocketIOClientSwift
|
||||
|
||||
class SocketBasicPacketTest: XCTestCase {
|
||||
let data = "test".dataUsingEncoding(NSUTF8StringEncoding)!
|
||||
let data2 = "test2".dataUsingEncoding(NSUTF8StringEncoding)!
|
||||
|
||||
func testEmpyEmit() {
|
||||
let expectedSendString = "2[\"test\"]"
|
||||
let sendData = ["test"]
|
||||
let packet = SocketPacket.packetFromEmit(sendData, id: -1, nsp: "/", ack: false)
|
||||
|
||||
XCTAssertEqual(packet.packetString, expectedSendString)
|
||||
}
|
||||
|
||||
func testNullEmit() {
|
||||
let expectedSendString = "2[\"test\",null]"
|
||||
let sendData = ["test", NSNull()]
|
||||
let packet = SocketPacket.packetFromEmit(sendData, id: -1, nsp: "/", ack: false)
|
||||
|
||||
XCTAssertEqual(packet.packetString, expectedSendString)
|
||||
}
|
||||
|
||||
func testStringEmit() {
|
||||
let expectedSendString = "2[\"test\",\"foo bar\"]"
|
||||
let sendData = ["test", "foo bar"]
|
||||
let packet = SocketPacket.packetFromEmit(sendData, id: -1, nsp: "/", ack: false)
|
||||
|
||||
XCTAssertEqual(packet.packetString, expectedSendString)
|
||||
}
|
||||
|
||||
func testStringEmitWithQuotes() {
|
||||
let expectedSendString = "2[\"test\",\"\\\"he\\\"llo world\\\"\"]"
|
||||
let sendData = ["test", "\"he\"llo world\""]
|
||||
let packet = SocketPacket.packetFromEmit(sendData, id: -1, nsp: "/", ack: false)
|
||||
|
||||
XCTAssertEqual(packet.packetString, expectedSendString)
|
||||
}
|
||||
|
||||
func testJSONEmit() {
|
||||
let expectedSendString = "2[\"test\",{\"test\":\"hello\",\"hello\":1,\"foobar\":true,\"null\":null}]"
|
||||
let sendData = ["test", ["foobar": true, "hello": 1, "test": "hello", "null": NSNull()]]
|
||||
let packet = SocketPacket.packetFromEmit(sendData, id: -1, nsp: "/", ack: false)
|
||||
|
||||
XCTAssertEqual(packet.packetString, expectedSendString)
|
||||
}
|
||||
|
||||
func testArrayEmit() {
|
||||
let expectedSendString = "2[\"test\",[\"hello\",1,{\"test\":\"test\"}]]"
|
||||
let sendData = ["test", ["hello", 1, ["test": "test"]]]
|
||||
let packet = SocketPacket.packetFromEmit(sendData, id: -1, nsp: "/", ack: false)
|
||||
|
||||
XCTAssertEqual(packet.packetString, expectedSendString)
|
||||
}
|
||||
|
||||
func testBinaryEmit() {
|
||||
let expectedSendString = "51-[\"test\",{\"num\":0,\"_placeholder\":true}]"
|
||||
let sendData = ["test", data]
|
||||
let packet = SocketPacket.packetFromEmit(sendData, id: -1, nsp: "/", ack: false)
|
||||
|
||||
XCTAssertEqual(packet.packetString, expectedSendString)
|
||||
XCTAssertEqual(packet.binary, [data])
|
||||
}
|
||||
|
||||
func testMultipleBinaryEmit() {
|
||||
let expectedSendString = "52-[\"test\",{\"data1\":{\"num\":0,\"_placeholder\":true},\"data2\":{\"num\":1,\"_placeholder\":true}}]"
|
||||
let sendData = ["test", ["data1": data, "data2": data2]]
|
||||
let packet = SocketPacket.packetFromEmit(sendData, id: -1, nsp: "/", ack: false)
|
||||
|
||||
XCTAssertEqual(packet.packetString, expectedSendString)
|
||||
XCTAssertEqual(packet.binary, [data, data2])
|
||||
}
|
||||
|
||||
func testEmitWithAck() {
|
||||
let expectedSendString = "20[\"test\"]"
|
||||
let sendData = ["test"]
|
||||
let packet = SocketPacket.packetFromEmit(sendData, id: 0, nsp: "/", ack: false)
|
||||
|
||||
XCTAssertEqual(packet.packetString, expectedSendString)
|
||||
}
|
||||
|
||||
func testEmitDataWithAck() {
|
||||
let expectedSendString = "51-0[\"test\",{\"num\":0,\"_placeholder\":true}]"
|
||||
let sendData = ["test", data]
|
||||
let packet = SocketPacket.packetFromEmit(sendData, id: 0, nsp: "/", ack: false)
|
||||
|
||||
XCTAssertEqual(packet.packetString, expectedSendString)
|
||||
XCTAssertEqual(packet.binary, [data])
|
||||
}
|
||||
|
||||
// Acks
|
||||
func testEmptyAck() {
|
||||
let expectedSendString = "30[]"
|
||||
let packet = SocketPacket.packetFromEmit([], id: 0, nsp: "/", ack: true)
|
||||
|
||||
XCTAssertEqual(packet.packetString, expectedSendString)
|
||||
}
|
||||
|
||||
func testNullAck() {
|
||||
let expectedSendString = "30[null]"
|
||||
let sendData = [NSNull()]
|
||||
let packet = SocketPacket.packetFromEmit(sendData, id: 0, nsp: "/", ack: true)
|
||||
|
||||
XCTAssertEqual(packet.packetString, expectedSendString)
|
||||
}
|
||||
|
||||
func testStringAck() {
|
||||
let expectedSendString = "30[\"test\"]"
|
||||
let sendData = ["test"]
|
||||
let packet = SocketPacket.packetFromEmit(sendData, id: 0, nsp: "/", ack: true)
|
||||
|
||||
XCTAssertEqual(packet.packetString, expectedSendString)
|
||||
}
|
||||
|
||||
func testJSONAck() {
|
||||
let expectedSendString = "30[{\"test\":\"hello\",\"hello\":1,\"foobar\":true,\"null\":null}]"
|
||||
let sendData = [["foobar": true, "hello": 1, "test": "hello", "null": NSNull()]]
|
||||
let packet = SocketPacket.packetFromEmit(sendData, id: 0, nsp: "/", ack: true)
|
||||
|
||||
XCTAssertEqual(packet.packetString, expectedSendString)
|
||||
}
|
||||
|
||||
func testBinaryAck() {
|
||||
let expectedSendString = "61-0[{\"num\":0,\"_placeholder\":true}]"
|
||||
let sendData = [data]
|
||||
let packet = SocketPacket.packetFromEmit(sendData, id: 0, nsp: "/", ack: true)
|
||||
|
||||
XCTAssertEqual(packet.packetString, expectedSendString)
|
||||
XCTAssertEqual(packet.binary, [data])
|
||||
}
|
||||
|
||||
func testMultipleBinaryAck() {
|
||||
let expectedSendString = "62-0[{\"data2\":{\"num\":0,\"_placeholder\":true},\"data1\":{\"num\":1,\"_placeholder\":true}}]"
|
||||
let sendData = [["data1": data, "data2": data2]]
|
||||
let packet = SocketPacket.packetFromEmit(sendData, id: 0, nsp: "/", ack: true)
|
||||
|
||||
XCTAssertEqual(packet.packetString, expectedSendString)
|
||||
XCTAssertEqual(packet.binary, [data2, data])
|
||||
}
|
||||
}
|
||||
@ -1,105 +0,0 @@
|
||||
//
|
||||
// SocketEngineTest.swift
|
||||
// Socket.IO-Client-Swift
|
||||
//
|
||||
// Created by Erik Little on 10/15/15.
|
||||
//
|
||||
//
|
||||
|
||||
import XCTest
|
||||
@testable import SocketIOClientSwift
|
||||
|
||||
class SocketEngineTest: XCTestCase {
|
||||
var client: SocketIOClient!
|
||||
var engine: SocketEngine!
|
||||
|
||||
override func setUp() {
|
||||
super.setUp()
|
||||
client = SocketIOClient(socketURL: NSURL(string: "http://localhost")!)
|
||||
engine = SocketEngine(client: client, url: NSURL(string: "http://localhost")!, options: nil)
|
||||
|
||||
client.setTestable()
|
||||
}
|
||||
|
||||
func testBasicPollingMessage() {
|
||||
let expectation = expectationWithDescription("Basic polling test")
|
||||
client.on("blankTest") {data, ack in
|
||||
expectation.fulfill()
|
||||
}
|
||||
|
||||
engine.parsePollingMessage("15:42[\"blankTest\"]")
|
||||
waitForExpectationsWithTimeout(3, handler: nil)
|
||||
}
|
||||
|
||||
func testTwoPacketsInOnePollTest() {
|
||||
let finalExpectation = expectationWithDescription("Final packet in poll test")
|
||||
var gotBlank = false
|
||||
|
||||
client.on("blankTest") {data, ack in
|
||||
gotBlank = true
|
||||
}
|
||||
|
||||
client.on("stringTest") {data, ack in
|
||||
if let str = data[0] as? String where gotBlank {
|
||||
if str == "hello" {
|
||||
finalExpectation.fulfill()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
engine.parsePollingMessage("15:42[\"blankTest\"]24:42[\"stringTest\",\"hello\"]")
|
||||
waitForExpectationsWithTimeout(3, handler: nil)
|
||||
}
|
||||
|
||||
func testEngineDoesErrorOnUnknownTransport() {
|
||||
let finalExpectation = expectationWithDescription("Unknown Transport")
|
||||
|
||||
client.on("error") {data, ack in
|
||||
if let error = data[0] as? String where error == "Unknown transport" {
|
||||
finalExpectation.fulfill()
|
||||
}
|
||||
}
|
||||
|
||||
engine.parseEngineMessage("{\"code\": 0, \"message\": \"Unknown transport\"}", fromPolling: false)
|
||||
waitForExpectationsWithTimeout(3, handler: nil)
|
||||
}
|
||||
|
||||
func testEngineDoesErrorOnUnknownMessage() {
|
||||
let finalExpectation = expectationWithDescription("Engine Errors")
|
||||
|
||||
client.on("error") {data, ack in
|
||||
finalExpectation.fulfill()
|
||||
}
|
||||
|
||||
engine.parseEngineMessage("afafafda", fromPolling: false)
|
||||
waitForExpectationsWithTimeout(3, handler: nil)
|
||||
}
|
||||
|
||||
func testEngineDecodesUTF8Properly() {
|
||||
let expectation = expectationWithDescription("Engine Decodes utf8")
|
||||
|
||||
client.on("stringTest") {data, ack in
|
||||
XCTAssertEqual(data[0] as? String, "lïne one\nlīne \rtwo", "Failed string test")
|
||||
expectation.fulfill()
|
||||
}
|
||||
|
||||
engine.parsePollingMessage("41:42[\"stringTest\",\"lïne one\\nlīne \\rtwo\"]")
|
||||
waitForExpectationsWithTimeout(3, handler: nil)
|
||||
}
|
||||
|
||||
func testEncodeURLProperly() {
|
||||
engine.connectParams = [
|
||||
"created": "2016-05-04T18:31:15+0200"
|
||||
]
|
||||
|
||||
XCTAssertEqual(engine.urlPolling.query, "transport=polling&b64=1&created=2016-05-04T18%3A31%3A15%2B0200")
|
||||
XCTAssertEqual(engine.urlWebSocket.query, "transport=websocket&created=2016-05-04T18%3A31%3A15%2B0200")
|
||||
|
||||
engine.connectParams = [
|
||||
"forbidden": "!*'();:@&=+$,/?%#[]\" {}"
|
||||
]
|
||||
|
||||
XCTAssertEqual(engine.urlPolling.query, "transport=polling&b64=1&forbidden=%21%2A%27%28%29%3B%3A%40%26%3D%2B%24%2C%2F%3F%25%23%5B%5D%22%20%7B%7D")
|
||||
XCTAssertEqual(engine.urlWebSocket.query, "transport=websocket&forbidden=%21%2A%27%28%29%3B%3A%40%26%3D%2B%24%2C%2F%3F%25%23%5B%5D%22%20%7B%7D")
|
||||
}
|
||||
}
|
||||
@ -1,140 +0,0 @@
|
||||
//
|
||||
// SocketNamespacePacketTest.swift
|
||||
// Socket.IO-Client-Swift
|
||||
//
|
||||
// Created by Erik Little on 10/11/15.
|
||||
//
|
||||
//
|
||||
|
||||
import XCTest
|
||||
@testable import SocketIOClientSwift
|
||||
|
||||
class SocketNamespacePacketTest: XCTestCase {
|
||||
let data = "test".dataUsingEncoding(NSUTF8StringEncoding)!
|
||||
let data2 = "test2".dataUsingEncoding(NSUTF8StringEncoding)!
|
||||
|
||||
func testEmpyEmit() {
|
||||
let expectedSendString = "2/swift,[\"test\"]"
|
||||
let sendData = ["test"]
|
||||
let packet = SocketPacket.packetFromEmit(sendData, id: -1, nsp: "/swift", ack: false)
|
||||
|
||||
XCTAssertEqual(packet.packetString, expectedSendString)
|
||||
}
|
||||
|
||||
func testNullEmit() {
|
||||
let expectedSendString = "2/swift,[\"test\",null]"
|
||||
let sendData = ["test", NSNull()]
|
||||
let packet = SocketPacket.packetFromEmit(sendData, id: -1, nsp: "/swift", ack: false)
|
||||
|
||||
XCTAssertEqual(packet.packetString, expectedSendString)
|
||||
}
|
||||
|
||||
func testStringEmit() {
|
||||
let expectedSendString = "2/swift,[\"test\",\"foo bar\"]"
|
||||
let sendData = ["test", "foo bar"]
|
||||
let packet = SocketPacket.packetFromEmit(sendData, id: -1, nsp: "/swift", ack: false)
|
||||
|
||||
XCTAssertEqual(packet.packetString, expectedSendString)
|
||||
}
|
||||
|
||||
func testJSONEmit() {
|
||||
let expectedSendString = "2/swift,[\"test\",{\"test\":\"hello\",\"hello\":1,\"foobar\":true,\"null\":null}]"
|
||||
let sendData = ["test", ["foobar": true, "hello": 1, "test": "hello", "null": NSNull()]]
|
||||
let packet = SocketPacket.packetFromEmit(sendData, id: -1, nsp: "/swift", ack: false)
|
||||
|
||||
XCTAssertEqual(packet.packetString, expectedSendString)
|
||||
}
|
||||
|
||||
func testArrayEmit() {
|
||||
let expectedSendString = "2/swift,[\"test\",[\"hello\",1,{\"test\":\"test\"}]]"
|
||||
let sendData = ["test", ["hello", 1, ["test": "test"]]]
|
||||
let packet = SocketPacket.packetFromEmit(sendData, id: -1, nsp: "/swift", ack: false)
|
||||
|
||||
XCTAssertEqual(packet.packetString, expectedSendString)
|
||||
}
|
||||
|
||||
func testBinaryEmit() {
|
||||
let expectedSendString = "51-/swift,[\"test\",{\"num\":0,\"_placeholder\":true}]"
|
||||
let sendData = ["test", data]
|
||||
let packet = SocketPacket.packetFromEmit(sendData, id: -1, nsp: "/swift", ack: false)
|
||||
|
||||
XCTAssertEqual(packet.packetString, expectedSendString)
|
||||
XCTAssertEqual(packet.binary, [data])
|
||||
}
|
||||
|
||||
func testMultipleBinaryEmit() {
|
||||
let expectedSendString = "52-/swift,[\"test\",{\"data1\":{\"num\":0,\"_placeholder\":true},\"data2\":{\"num\":1,\"_placeholder\":true}}]"
|
||||
let sendData = ["test", ["data1": data, "data2": data2]]
|
||||
let packet = SocketPacket.packetFromEmit(sendData, id: -1, nsp: "/swift", ack: false)
|
||||
|
||||
XCTAssertEqual(packet.packetString, expectedSendString)
|
||||
XCTAssertEqual(packet.binary, [data, data2])
|
||||
}
|
||||
|
||||
func testEmitWithAck() {
|
||||
let expectedSendString = "2/swift,0[\"test\"]"
|
||||
let sendData = ["test"]
|
||||
let packet = SocketPacket.packetFromEmit(sendData, id: 0, nsp: "/swift", ack: false)
|
||||
|
||||
XCTAssertEqual(packet.packetString, expectedSendString)
|
||||
}
|
||||
|
||||
func testEmitDataWithAck() {
|
||||
let expectedSendString = "51-/swift,0[\"test\",{\"num\":0,\"_placeholder\":true}]"
|
||||
let sendData = ["test", data]
|
||||
let packet = SocketPacket.packetFromEmit(sendData, id: 0, nsp: "/swift", ack: false)
|
||||
|
||||
XCTAssertEqual(packet.packetString, expectedSendString)
|
||||
XCTAssertEqual(packet.binary, [data])
|
||||
}
|
||||
|
||||
// Acks
|
||||
func testEmptyAck() {
|
||||
let expectedSendString = "3/swift,0[]"
|
||||
let packet = SocketPacket.packetFromEmit([], id: 0, nsp: "/swift", ack: true)
|
||||
|
||||
XCTAssertEqual(packet.packetString, expectedSendString)
|
||||
}
|
||||
|
||||
func testNullAck() {
|
||||
let expectedSendString = "3/swift,0[null]"
|
||||
let sendData = [NSNull()]
|
||||
let packet = SocketPacket.packetFromEmit(sendData, id: 0, nsp: "/swift", ack: true)
|
||||
|
||||
XCTAssertEqual(packet.packetString, expectedSendString)
|
||||
}
|
||||
|
||||
func testStringAck() {
|
||||
let expectedSendString = "3/swift,0[\"test\"]"
|
||||
let sendData = ["test"]
|
||||
let packet = SocketPacket.packetFromEmit(sendData, id: 0, nsp: "/swift", ack: true)
|
||||
|
||||
XCTAssertEqual(packet.packetString, expectedSendString)
|
||||
}
|
||||
|
||||
func testJSONAck() {
|
||||
let expectedSendString = "3/swift,0[{\"test\":\"hello\",\"hello\":1,\"foobar\":true,\"null\":null}]"
|
||||
let sendData = [["foobar": true, "hello": 1, "test": "hello", "null": NSNull()]]
|
||||
let packet = SocketPacket.packetFromEmit(sendData, id: 0, nsp: "/swift", ack: true)
|
||||
|
||||
XCTAssertEqual(packet.packetString, expectedSendString)
|
||||
}
|
||||
|
||||
func testBinaryAck() {
|
||||
let expectedSendString = "61-/swift,0[{\"num\":0,\"_placeholder\":true}]"
|
||||
let sendData = [data]
|
||||
let packet = SocketPacket.packetFromEmit(sendData, id: 0, nsp: "/swift", ack: true)
|
||||
|
||||
XCTAssertEqual(packet.packetString, expectedSendString)
|
||||
XCTAssertEqual(packet.binary, [data])
|
||||
}
|
||||
|
||||
func testMultipleBinaryAck() {
|
||||
let expectedSendString = "62-/swift,0[{\"data2\":{\"num\":0,\"_placeholder\":true},\"data1\":{\"num\":1,\"_placeholder\":true}}]"
|
||||
let sendData = [["data1": data, "data2": data2]]
|
||||
let packet = SocketPacket.packetFromEmit(sendData, id: 0, nsp: "/swift", ack: true)
|
||||
|
||||
XCTAssertEqual(packet.packetString, expectedSendString)
|
||||
XCTAssertEqual(packet.binary, [data2, data])
|
||||
}
|
||||
}
|
||||
@ -1,47 +0,0 @@
|
||||
//
|
||||
// SocketObjectiveCTest.m
|
||||
// Socket.IO-Client-Swift
|
||||
//
|
||||
// Created by Erik Little on 3/25/16.
|
||||
//
|
||||
// Merely tests whether the Objective-C api breaks
|
||||
//
|
||||
|
||||
#import <XCTest/XCTest.h>
|
||||
@import SocketIOClientSwift;
|
||||
|
||||
@interface SocketObjectiveCTest : XCTestCase
|
||||
|
||||
@property SocketIOClient* socket;
|
||||
|
||||
@end
|
||||
|
||||
@implementation SocketObjectiveCTest
|
||||
|
||||
- (void)setUp {
|
||||
[super setUp];
|
||||
NSURL* url = [[NSURL alloc] initWithString:@"http://localhost"];
|
||||
self.socket = [[SocketIOClient alloc] initWithSocketURL:url options:nil];
|
||||
}
|
||||
|
||||
- (void)testOnSyntax {
|
||||
[self.socket on:@"someCallback" callback:^(NSArray* data, SocketAckEmitter* ack) {
|
||||
[ack with:@[@1]];
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)testEmitSyntax {
|
||||
[self.socket emit:@"testEmit" withItems:@[@YES]];
|
||||
}
|
||||
|
||||
- (void)testEmitWithAckSyntax {
|
||||
[self.socket emitWithAck:@"testAckEmit" withItems:@[@YES]](0, ^(NSArray* data) {
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
- (void)testOffSyntax {
|
||||
[self.socket off:@"test"];
|
||||
}
|
||||
|
||||
@end
|
||||
@ -1,156 +0,0 @@
|
||||
//
|
||||
// SocketSideEffectTest.swift
|
||||
// Socket.IO-Client-Swift
|
||||
//
|
||||
// Created by Erik Little on 10/11/15.
|
||||
//
|
||||
//
|
||||
|
||||
import XCTest
|
||||
@testable import SocketIOClientSwift
|
||||
|
||||
class SocketSideEffectTest: XCTestCase {
|
||||
let data = "test".dataUsingEncoding(NSUTF8StringEncoding)!
|
||||
let data2 = "test2".dataUsingEncoding(NSUTF8StringEncoding)!
|
||||
private var socket: SocketIOClient!
|
||||
|
||||
override func setUp() {
|
||||
super.setUp()
|
||||
socket = SocketIOClient(socketURL: NSURL())
|
||||
socket.setTestable()
|
||||
}
|
||||
|
||||
func testInitialCurrentAck() {
|
||||
XCTAssertEqual(socket.currentAck, -1)
|
||||
}
|
||||
|
||||
func testFirstAck() {
|
||||
socket.emitWithAck("test")(timeoutAfter: 0) {data in}
|
||||
XCTAssertEqual(socket.currentAck, 0)
|
||||
}
|
||||
|
||||
func testSecondAck() {
|
||||
socket.emitWithAck("test")(timeoutAfter: 0) {data in}
|
||||
socket.emitWithAck("test")(timeoutAfter: 0) {data in}
|
||||
|
||||
XCTAssertEqual(socket.currentAck, 1)
|
||||
}
|
||||
|
||||
func testHandleAck() {
|
||||
let expectation = expectationWithDescription("handled ack")
|
||||
socket.emitWithAck("test")(timeoutAfter: 0) {data in
|
||||
XCTAssertEqual(data[0] as? String, "hello world")
|
||||
expectation.fulfill()
|
||||
}
|
||||
|
||||
socket.parseSocketMessage("30[\"hello world\"]")
|
||||
waitForExpectationsWithTimeout(3, handler: nil)
|
||||
}
|
||||
|
||||
func testHandleAck2() {
|
||||
let expectation = expectationWithDescription("handled ack2")
|
||||
socket.emitWithAck("test")(timeoutAfter: 0) {data in
|
||||
XCTAssertTrue(data.count == 2, "Wrong number of ack items")
|
||||
expectation.fulfill()
|
||||
}
|
||||
|
||||
socket.parseSocketMessage("61-0[{\"_placeholder\":true,\"num\":0},{\"test\":true}]")
|
||||
socket.parseBinaryData(NSData())
|
||||
waitForExpectationsWithTimeout(3, handler: nil)
|
||||
}
|
||||
|
||||
func testHandleEvent() {
|
||||
let expectation = expectationWithDescription("handled event")
|
||||
socket.on("test") {data, ack in
|
||||
XCTAssertEqual(data[0] as? String, "hello world")
|
||||
expectation.fulfill()
|
||||
}
|
||||
|
||||
socket.parseSocketMessage("2[\"test\",\"hello world\"]")
|
||||
waitForExpectationsWithTimeout(3, handler: nil)
|
||||
}
|
||||
|
||||
func testHandleStringEventWithQuotes() {
|
||||
let expectation = expectationWithDescription("handled event")
|
||||
socket.on("test") {data, ack in
|
||||
XCTAssertEqual(data[0] as? String, "\"hello world\"")
|
||||
expectation.fulfill()
|
||||
}
|
||||
|
||||
socket.parseSocketMessage("2[\"test\",\"\\\"hello world\\\"\"]")
|
||||
waitForExpectationsWithTimeout(3, handler: nil)
|
||||
}
|
||||
|
||||
func testHandleOnceEvent() {
|
||||
let expectation = expectationWithDescription("handled event")
|
||||
socket.once("test") {data, ack in
|
||||
XCTAssertEqual(data[0] as? String, "hello world")
|
||||
XCTAssertEqual(self.socket.testHandlers.count, 0)
|
||||
expectation.fulfill()
|
||||
}
|
||||
|
||||
socket.parseSocketMessage("2[\"test\",\"hello world\"]")
|
||||
waitForExpectationsWithTimeout(3, handler: nil)
|
||||
}
|
||||
|
||||
func testOffWithEvent() {
|
||||
socket.on("test") {data, ack in }
|
||||
XCTAssertEqual(socket.testHandlers.count, 1)
|
||||
socket.on("test") {data, ack in }
|
||||
XCTAssertEqual(socket.testHandlers.count, 2)
|
||||
socket.off("test")
|
||||
XCTAssertEqual(socket.testHandlers.count, 0)
|
||||
}
|
||||
|
||||
func testOffWithId() {
|
||||
let handler = socket.on("test") {data, ack in }
|
||||
XCTAssertEqual(socket.testHandlers.count, 1)
|
||||
socket.on("test") {data, ack in }
|
||||
XCTAssertEqual(socket.testHandlers.count, 2)
|
||||
socket.off(id: handler)
|
||||
XCTAssertEqual(socket.testHandlers.count, 1)
|
||||
}
|
||||
|
||||
func testHandlesErrorPacket() {
|
||||
let expectation = expectationWithDescription("Handled error")
|
||||
socket.on("error") {data, ack in
|
||||
if let error = data[0] as? String where error == "test error" {
|
||||
expectation.fulfill()
|
||||
}
|
||||
}
|
||||
|
||||
socket.parseSocketMessage("4\"test error\"")
|
||||
waitForExpectationsWithTimeout(3, handler: nil)
|
||||
}
|
||||
|
||||
func testHandleBinaryEvent() {
|
||||
let expectation = expectationWithDescription("handled binary event")
|
||||
socket.on("test") {data, ack in
|
||||
if let dict = data[0] as? NSDictionary, data = dict["test"] as? NSData {
|
||||
XCTAssertEqual(data, self.data)
|
||||
expectation.fulfill()
|
||||
}
|
||||
}
|
||||
|
||||
socket.parseSocketMessage("51-[\"test\",{\"test\":{\"_placeholder\":true,\"num\":0}}]")
|
||||
socket.parseBinaryData(data)
|
||||
waitForExpectationsWithTimeout(3, handler: nil)
|
||||
}
|
||||
|
||||
func testHandleMultipleBinaryEvent() {
|
||||
let expectation = expectationWithDescription("handled multiple binary event")
|
||||
socket.on("test") {data, ack in
|
||||
if let dict = data[0] as? NSDictionary, data = dict["test"] as? NSData,
|
||||
data2 = dict["test2"] as? NSData {
|
||||
XCTAssertEqual(data, self.data)
|
||||
XCTAssertEqual(data2, self.data2)
|
||||
expectation.fulfill()
|
||||
}
|
||||
}
|
||||
|
||||
socket.parseSocketMessage("52-[\"test\",{\"test\":{\"_placeholder\":true,\"num\":0},\"test2\":{\"_placeholder\":true,\"num\":1}}]")
|
||||
socket.parseBinaryData(data)
|
||||
socket.parseBinaryData(data2)
|
||||
waitForExpectationsWithTimeout(3, handler: nil)
|
||||
}
|
||||
}
|
||||
@ -1,26 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>en</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>$(EXECUTABLE_NAME)</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>$(PRODUCT_NAME)</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>FMWK</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.0</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>$(CURRENT_PROJECT_VERSION)</string>
|
||||
<key>NSPrincipalClass</key>
|
||||
<string></string>
|
||||
</dict>
|
||||
</plist>
|
||||
@ -1,19 +0,0 @@
|
||||
//
|
||||
// SocketIO-iOS.h
|
||||
// SocketIO-iOS
|
||||
//
|
||||
// Created by Nacho Soto on 7/11/15.
|
||||
//
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
//! Project version number for SocketIO-iOS.
|
||||
FOUNDATION_EXPORT double SocketIO_iOSVersionNumber;
|
||||
|
||||
//! Project version string for SocketIO-iOS.
|
||||
FOUNDATION_EXPORT const unsigned char SocketIO_iOSVersionString[];
|
||||
|
||||
// In this header, you should import all the public headers of your framework using statements like #import <SocketIO_iOS/PublicHeader.h>
|
||||
|
||||
|
||||
@ -1,24 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>en</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>$(EXECUTABLE_NAME)</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>$(PRODUCT_NAME)</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>BNDL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.0</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1</string>
|
||||
</dict>
|
||||
</plist>
|
||||
@ -6,7 +6,7 @@
|
||||
//
|
||||
//
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
//! Project version number for SocketIO-Mac.
|
||||
FOUNDATION_EXPORT double SocketIO_MacVersionNumber;
|
||||
@ -1,31 +0,0 @@
|
||||
//
|
||||
// NSCharacterSet.swift
|
||||
// Socket.IO-Client-Swift
|
||||
//
|
||||
// Created by Yannick Loriot on 5/4/16.
|
||||
//
|
||||
// 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.
|
||||
|
||||
import Foundation
|
||||
|
||||
extension NSCharacterSet {
|
||||
class var allowedURLCharacterSet: NSCharacterSet {
|
||||
return NSCharacterSet(charactersInString: "!*'();:@&=+$,/?%#[]\" {}").invertedSet
|
||||
}
|
||||
}
|
||||
@ -1,47 +0,0 @@
|
||||
//
|
||||
// SocketAckEmitter.swift
|
||||
// Socket.IO-Client-Swift
|
||||
//
|
||||
// Created by Erik Little on 9/16/15.
|
||||
//
|
||||
// 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.
|
||||
|
||||
import Foundation
|
||||
|
||||
public final class SocketAckEmitter : NSObject {
|
||||
let socket: SocketIOClient
|
||||
let ackNum: Int
|
||||
|
||||
init(socket: SocketIOClient, ackNum: Int) {
|
||||
self.socket = socket
|
||||
self.ackNum = ackNum
|
||||
}
|
||||
|
||||
public func with(items: AnyObject...) {
|
||||
guard ackNum != -1 else { return }
|
||||
|
||||
socket.emitAck(ackNum, withItems: items)
|
||||
}
|
||||
|
||||
public func with(items: [AnyObject]) {
|
||||
guard ackNum != -1 else { return }
|
||||
|
||||
socket.emitAck(ackNum, withItems: items)
|
||||
}
|
||||
}
|
||||
@ -1,551 +0,0 @@
|
||||
//
|
||||
// SocketEngine.swift
|
||||
// Socket.IO-Client-Swift
|
||||
//
|
||||
// Created by Erik Little on 3/3/15.
|
||||
//
|
||||
// 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.
|
||||
|
||||
import Foundation
|
||||
|
||||
public final class SocketEngine : NSObject, SocketEnginePollable, SocketEngineWebsocket {
|
||||
public let emitQueue = dispatch_queue_create("com.socketio.engineEmitQueue", DISPATCH_QUEUE_SERIAL)
|
||||
public let handleQueue = dispatch_queue_create("com.socketio.engineHandleQueue", DISPATCH_QUEUE_SERIAL)
|
||||
public let parseQueue = dispatch_queue_create("com.socketio.engineParseQueue", DISPATCH_QUEUE_SERIAL)
|
||||
|
||||
public var connectParams: [String: AnyObject]? {
|
||||
didSet {
|
||||
(urlPolling, urlWebSocket) = createURLs()
|
||||
}
|
||||
}
|
||||
|
||||
public var postWait = [String]()
|
||||
public var waitingForPoll = false
|
||||
public var waitingForPost = false
|
||||
|
||||
public private(set) var closed = false
|
||||
public private(set) var connected = false
|
||||
public private(set) var cookies: [NSHTTPCookie]?
|
||||
public private(set) var doubleEncodeUTF8 = true
|
||||
public private(set) var extraHeaders: [String: String]?
|
||||
public private(set) var fastUpgrade = false
|
||||
public private(set) var forcePolling = false
|
||||
public private(set) var forceWebsockets = false
|
||||
public private(set) var invalidated = false
|
||||
public private(set) var polling = true
|
||||
public private(set) var probing = false
|
||||
public private(set) var session: NSURLSession?
|
||||
public private(set) var sid = ""
|
||||
public private(set) var socketPath = "/engine.io/"
|
||||
public private(set) var urlPolling = NSURL()
|
||||
public private(set) var urlWebSocket = NSURL()
|
||||
public private(set) var websocket = false
|
||||
public private(set) var ws: WebSocket?
|
||||
|
||||
public weak var client: SocketEngineClient?
|
||||
|
||||
private weak var sessionDelegate: NSURLSessionDelegate?
|
||||
|
||||
private typealias Probe = (msg: String, type: SocketEnginePacketType, data: [NSData])
|
||||
private typealias ProbeWaitQueue = [Probe]
|
||||
|
||||
private let logType = "SocketEngine"
|
||||
private let url: NSURL
|
||||
|
||||
private var pingInterval: Double?
|
||||
private var pingTimeout = 0.0 {
|
||||
didSet {
|
||||
pongsMissedMax = Int(pingTimeout / (pingInterval ?? 25))
|
||||
}
|
||||
}
|
||||
private var pongsMissed = 0
|
||||
private var pongsMissedMax = 0
|
||||
private var probeWait = ProbeWaitQueue()
|
||||
private var secure = false
|
||||
private var selfSigned = false
|
||||
private var voipEnabled = false
|
||||
|
||||
public init(client: SocketEngineClient, url: NSURL, options: Set<SocketIOClientOption>) {
|
||||
self.client = client
|
||||
self.url = url
|
||||
|
||||
for option in options {
|
||||
switch option {
|
||||
case let .ConnectParams(params):
|
||||
connectParams = params
|
||||
case let .Cookies(cookies):
|
||||
self.cookies = cookies
|
||||
case let .DoubleEncodeUTF8(encode):
|
||||
doubleEncodeUTF8 = encode
|
||||
case let .ExtraHeaders(headers):
|
||||
extraHeaders = headers
|
||||
case let .SessionDelegate(delegate):
|
||||
sessionDelegate = delegate
|
||||
case let .ForcePolling(force):
|
||||
forcePolling = force
|
||||
case let .ForceWebsockets(force):
|
||||
forceWebsockets = force
|
||||
case let .Path(path):
|
||||
socketPath = path
|
||||
case let .VoipEnabled(enable):
|
||||
voipEnabled = enable
|
||||
case let .Secure(secure):
|
||||
self.secure = secure
|
||||
case let .SelfSigned(selfSigned):
|
||||
self.selfSigned = selfSigned
|
||||
default:
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
super.init()
|
||||
|
||||
(urlPolling, urlWebSocket) = createURLs()
|
||||
}
|
||||
|
||||
public convenience init(client: SocketEngineClient, url: NSURL, options: NSDictionary?) {
|
||||
self.init(client: client, url: url, options: options?.toSocketOptionsSet() ?? [])
|
||||
}
|
||||
|
||||
deinit {
|
||||
DefaultSocketLogger.Logger.log("Engine is being released", type: logType)
|
||||
closed = true
|
||||
stopPolling()
|
||||
}
|
||||
|
||||
private func checkAndHandleEngineError(msg: String) {
|
||||
guard let stringData = msg.dataUsingEncoding(NSUTF8StringEncoding,
|
||||
allowLossyConversion: false) else { return }
|
||||
|
||||
do {
|
||||
if let dict = try NSJSONSerialization.JSONObjectWithData(stringData, options: .MutableContainers) as? NSDictionary {
|
||||
guard let error = dict["message"] as? String else { return }
|
||||
|
||||
/*
|
||||
0: Unknown transport
|
||||
1: Unknown sid
|
||||
2: Bad handshake request
|
||||
3: Bad request
|
||||
*/
|
||||
didError(error)
|
||||
}
|
||||
} catch {
|
||||
didError("Got unknown error from server \(msg)")
|
||||
}
|
||||
}
|
||||
|
||||
private func checkIfMessageIsBase64Binary(message: String) -> Bool {
|
||||
if message.hasPrefix("b4") {
|
||||
// binary in base64 string
|
||||
let noPrefix = message[message.startIndex.advancedBy(2)..<message.endIndex]
|
||||
|
||||
if let data = NSData(base64EncodedString: noPrefix,
|
||||
options: .IgnoreUnknownCharacters) {
|
||||
client?.parseEngineBinaryData(data)
|
||||
}
|
||||
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
/// Starts the connection to the server
|
||||
public func connect() {
|
||||
if connected {
|
||||
DefaultSocketLogger.Logger.error("Engine tried opening while connected. Assuming this was a reconnect", type: logType)
|
||||
disconnect("reconnect")
|
||||
}
|
||||
|
||||
DefaultSocketLogger.Logger.log("Starting engine", type: logType)
|
||||
DefaultSocketLogger.Logger.log("Handshaking", type: logType)
|
||||
|
||||
resetEngine()
|
||||
|
||||
if forceWebsockets {
|
||||
polling = false
|
||||
websocket = true
|
||||
createWebsocketAndConnect()
|
||||
return
|
||||
}
|
||||
|
||||
let reqPolling = NSMutableURLRequest(URL: urlPolling)
|
||||
|
||||
if cookies != nil {
|
||||
let headers = NSHTTPCookie.requestHeaderFieldsWithCookies(cookies!)
|
||||
reqPolling.allHTTPHeaderFields = headers
|
||||
}
|
||||
|
||||
if let extraHeaders = extraHeaders {
|
||||
for (headerName, value) in extraHeaders {
|
||||
reqPolling.setValue(value, forHTTPHeaderField: headerName)
|
||||
}
|
||||
}
|
||||
|
||||
dispatch_async(emitQueue) {
|
||||
self.doLongPoll(reqPolling)
|
||||
}
|
||||
}
|
||||
|
||||
private func createURLs() -> (NSURL, NSURL) {
|
||||
if client == nil {
|
||||
return (NSURL(), NSURL())
|
||||
}
|
||||
|
||||
let urlPolling = NSURLComponents(string: url.absoluteString)!
|
||||
let urlWebSocket = NSURLComponents(string: url.absoluteString)!
|
||||
var queryString = ""
|
||||
|
||||
urlWebSocket.path = socketPath
|
||||
urlPolling.path = socketPath
|
||||
|
||||
if secure {
|
||||
urlPolling.scheme = "https"
|
||||
urlWebSocket.scheme = "wss"
|
||||
} else {
|
||||
urlPolling.scheme = "http"
|
||||
urlWebSocket.scheme = "ws"
|
||||
}
|
||||
|
||||
if connectParams != nil {
|
||||
for (key, value) in connectParams! {
|
||||
let keyEsc = key.urlEncode()!
|
||||
let valueEsc = "\(value)".urlEncode()!
|
||||
|
||||
queryString += "&\(keyEsc)=\(valueEsc)"
|
||||
}
|
||||
}
|
||||
|
||||
urlWebSocket.percentEncodedQuery = "transport=websocket" + queryString
|
||||
urlPolling.percentEncodedQuery = "transport=polling&b64=1" + queryString
|
||||
|
||||
return (urlPolling.URL!, urlWebSocket.URL!)
|
||||
}
|
||||
|
||||
private func createWebsocketAndConnect() {
|
||||
ws = WebSocket(url: urlWebSocketWithSid)
|
||||
|
||||
if cookies != nil {
|
||||
let headers = NSHTTPCookie.requestHeaderFieldsWithCookies(cookies!)
|
||||
for (key, value) in headers {
|
||||
ws?.headers[key] = value
|
||||
}
|
||||
}
|
||||
|
||||
if extraHeaders != nil {
|
||||
for (headerName, value) in extraHeaders! {
|
||||
ws?.headers[headerName] = value
|
||||
}
|
||||
}
|
||||
|
||||
ws?.queue = handleQueue
|
||||
ws?.voipEnabled = voipEnabled
|
||||
ws?.delegate = self
|
||||
ws?.selfSignedSSL = selfSigned
|
||||
|
||||
ws?.connect()
|
||||
}
|
||||
|
||||
public func didError(error: String) {
|
||||
DefaultSocketLogger.Logger.error(error, type: logType)
|
||||
client?.engineDidError(error)
|
||||
disconnect(error)
|
||||
}
|
||||
|
||||
public func disconnect(reason: String) {
|
||||
func postSendClose(data: NSData?, _ res: NSURLResponse?, _ err: NSError?) {
|
||||
sid = ""
|
||||
closed = true
|
||||
invalidated = true
|
||||
connected = false
|
||||
|
||||
ws?.disconnect()
|
||||
stopPolling()
|
||||
client?.engineDidClose(reason)
|
||||
}
|
||||
|
||||
DefaultSocketLogger.Logger.log("Engine is being closed.", type: logType)
|
||||
|
||||
if closed {
|
||||
client?.engineDidClose(reason)
|
||||
return
|
||||
}
|
||||
|
||||
if websocket {
|
||||
sendWebSocketMessage("", withType: .Close, withData: [])
|
||||
postSendClose(nil, nil, nil)
|
||||
} else {
|
||||
// We need to take special care when we're polling that we send it ASAP
|
||||
// Also make sure we're on the emitQueue since we're touching postWait
|
||||
dispatch_sync(emitQueue) {
|
||||
self.postWait.append(String(SocketEnginePacketType.Close.rawValue))
|
||||
let req = self.createRequestForPostWithPostWait()
|
||||
self.doRequest(req, withCallback: postSendClose)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public func doFastUpgrade() {
|
||||
if waitingForPoll {
|
||||
DefaultSocketLogger.Logger.error("Outstanding poll when switched to WebSockets," +
|
||||
"we'll probably disconnect soon. You should report this.", type: logType)
|
||||
}
|
||||
|
||||
sendWebSocketMessage("", withType: .Upgrade, withData: [])
|
||||
websocket = true
|
||||
polling = false
|
||||
fastUpgrade = false
|
||||
probing = false
|
||||
flushProbeWait()
|
||||
}
|
||||
|
||||
private func flushProbeWait() {
|
||||
DefaultSocketLogger.Logger.log("Flushing probe wait", type: logType)
|
||||
|
||||
dispatch_async(emitQueue) {
|
||||
for waiter in self.probeWait {
|
||||
self.write(waiter.msg, withType: waiter.type, withData: waiter.data)
|
||||
}
|
||||
|
||||
self.probeWait.removeAll(keepCapacity: false)
|
||||
|
||||
if self.postWait.count != 0 {
|
||||
self.flushWaitingForPostToWebSocket()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// We had packets waiting for send when we upgraded
|
||||
// Send them raw
|
||||
public func flushWaitingForPostToWebSocket() {
|
||||
guard let ws = self.ws else { return }
|
||||
|
||||
for msg in postWait {
|
||||
ws.writeString(fixDoubleUTF8(msg))
|
||||
}
|
||||
|
||||
postWait.removeAll(keepCapacity: true)
|
||||
}
|
||||
|
||||
private func handleClose(reason: String) {
|
||||
client?.engineDidClose(reason)
|
||||
}
|
||||
|
||||
private func handleMessage(message: String) {
|
||||
client?.parseEngineMessage(message)
|
||||
}
|
||||
|
||||
private func handleNOOP() {
|
||||
doPoll()
|
||||
}
|
||||
|
||||
private func handleOpen(openData: String) {
|
||||
let mesData = openData.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)!
|
||||
do {
|
||||
let json = try NSJSONSerialization.JSONObjectWithData(mesData,
|
||||
options: NSJSONReadingOptions.AllowFragments) as? NSDictionary
|
||||
if let sid = json?["sid"] as? String {
|
||||
let upgradeWs: Bool
|
||||
|
||||
self.sid = sid
|
||||
connected = true
|
||||
|
||||
if let upgrades = json?["upgrades"] as? [String] {
|
||||
upgradeWs = upgrades.contains("websocket")
|
||||
} else {
|
||||
upgradeWs = false
|
||||
}
|
||||
|
||||
if let pingInterval = json?["pingInterval"] as? Double, pingTimeout = json?["pingTimeout"] as? Double {
|
||||
self.pingInterval = pingInterval / 1000.0
|
||||
self.pingTimeout = pingTimeout / 1000.0
|
||||
}
|
||||
|
||||
if !forcePolling && !forceWebsockets && upgradeWs {
|
||||
createWebsocketAndConnect()
|
||||
}
|
||||
|
||||
sendPing()
|
||||
|
||||
if !forceWebsockets {
|
||||
doPoll()
|
||||
}
|
||||
|
||||
client?.engineDidOpen?("Connect")
|
||||
}
|
||||
} catch {
|
||||
didError("Error parsing open packet")
|
||||
}
|
||||
}
|
||||
|
||||
private func handlePong(pongMessage: String) {
|
||||
pongsMissed = 0
|
||||
|
||||
// We should upgrade
|
||||
if pongMessage == "3probe" {
|
||||
upgradeTransport()
|
||||
}
|
||||
}
|
||||
|
||||
public func parseEngineData(data: NSData) {
|
||||
DefaultSocketLogger.Logger.log("Got binary data: %@", type: "SocketEngine", args: data)
|
||||
client?.parseEngineBinaryData(data.subdataWithRange(NSMakeRange(1, data.length - 1)))
|
||||
}
|
||||
|
||||
public func parseEngineMessage(message: String, fromPolling: Bool) {
|
||||
DefaultSocketLogger.Logger.log("Got message: %@", type: logType, args: message)
|
||||
|
||||
let reader = SocketStringReader(message: message)
|
||||
let fixedString: String
|
||||
|
||||
guard let type = SocketEnginePacketType(rawValue: Int(reader.currentCharacter) ?? -1) else {
|
||||
if !checkIfMessageIsBase64Binary(message) {
|
||||
checkAndHandleEngineError(message)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
if fromPolling && type != .Noop && doubleEncodeUTF8 {
|
||||
fixedString = fixDoubleUTF8(message)
|
||||
} else {
|
||||
fixedString = message
|
||||
}
|
||||
|
||||
switch type {
|
||||
case .Message:
|
||||
handleMessage(fixedString[fixedString.startIndex.successor()..<fixedString.endIndex])
|
||||
case .Noop:
|
||||
handleNOOP()
|
||||
case .Pong:
|
||||
handlePong(fixedString)
|
||||
case .Open:
|
||||
handleOpen(fixedString[fixedString.startIndex.successor()..<fixedString.endIndex])
|
||||
case .Close:
|
||||
handleClose(fixedString)
|
||||
default:
|
||||
DefaultSocketLogger.Logger.log("Got unknown packet type", type: logType)
|
||||
}
|
||||
}
|
||||
|
||||
// Puts the engine back in its default state
|
||||
private func resetEngine() {
|
||||
closed = false
|
||||
connected = false
|
||||
fastUpgrade = false
|
||||
polling = true
|
||||
probing = false
|
||||
invalidated = false
|
||||
session = NSURLSession(configuration: .defaultSessionConfiguration(),
|
||||
delegate: sessionDelegate,
|
||||
delegateQueue: NSOperationQueue())
|
||||
sid = ""
|
||||
waitingForPoll = false
|
||||
waitingForPost = false
|
||||
websocket = false
|
||||
}
|
||||
|
||||
private func sendPing() {
|
||||
if !connected {
|
||||
return
|
||||
}
|
||||
|
||||
//Server is not responding
|
||||
if pongsMissed > pongsMissedMax {
|
||||
client?.engineDidClose("Ping timeout")
|
||||
return
|
||||
}
|
||||
|
||||
if let pingInterval = pingInterval {
|
||||
pongsMissed += 1
|
||||
write("", withType: .Ping, withData: [])
|
||||
|
||||
let time = dispatch_time(DISPATCH_TIME_NOW, Int64(pingInterval * Double(NSEC_PER_SEC)))
|
||||
dispatch_after(time, dispatch_get_main_queue()) {[weak self] in
|
||||
self?.sendPing()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Moves from long-polling to websockets
|
||||
private func upgradeTransport() {
|
||||
if ws?.isConnected ?? false {
|
||||
DefaultSocketLogger.Logger.log("Upgrading transport to WebSockets", type: logType)
|
||||
|
||||
fastUpgrade = true
|
||||
sendPollMessage("", withType: .Noop, withData: [])
|
||||
// After this point, we should not send anymore polling messages
|
||||
}
|
||||
}
|
||||
|
||||
/// Write a message, independent of transport.
|
||||
public func write(msg: String, withType type: SocketEnginePacketType, withData data: [NSData]) {
|
||||
dispatch_async(emitQueue) {
|
||||
guard self.connected else { return }
|
||||
|
||||
if self.websocket {
|
||||
DefaultSocketLogger.Logger.log("Writing ws: %@ has data: %@",
|
||||
type: self.logType, args: msg, data.count != 0)
|
||||
self.sendWebSocketMessage(msg, withType: type, withData: data)
|
||||
} else if !self.probing {
|
||||
DefaultSocketLogger.Logger.log("Writing poll: %@ has data: %@",
|
||||
type: self.logType, args: msg, data.count != 0)
|
||||
self.sendPollMessage(msg, withType: type, withData: data)
|
||||
} else {
|
||||
self.probeWait.append((msg, type, data))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Delegate methods
|
||||
public func websocketDidConnect(socket: WebSocket) {
|
||||
if !forceWebsockets {
|
||||
probing = true
|
||||
probeWebSocket()
|
||||
} else {
|
||||
connected = true
|
||||
probing = false
|
||||
polling = false
|
||||
}
|
||||
}
|
||||
|
||||
public func websocketDidDisconnect(socket: WebSocket, error: NSError?) {
|
||||
probing = false
|
||||
|
||||
if closed {
|
||||
client?.engineDidClose("Disconnect")
|
||||
return
|
||||
}
|
||||
|
||||
if websocket {
|
||||
connected = false
|
||||
websocket = false
|
||||
|
||||
let reason = error?.localizedDescription ?? "Socket Disconnected"
|
||||
|
||||
if error != nil {
|
||||
didError(reason)
|
||||
}
|
||||
|
||||
client?.engineDidClose(reason)
|
||||
} else {
|
||||
flushProbeWait()
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,34 +0,0 @@
|
||||
//
|
||||
// SocketEngineClient.swift
|
||||
// Socket.IO-Client-Swift
|
||||
//
|
||||
// Created by Erik Little on 3/19/15.
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
@objc public protocol SocketEngineClient {
|
||||
func engineDidError(reason: String)
|
||||
func engineDidClose(reason: String)
|
||||
optional func engineDidOpen(reason: String)
|
||||
func parseEngineMessage(msg: String)
|
||||
func parseEngineBinaryData(data: NSData)
|
||||
}
|
||||
@ -1,236 +0,0 @@
|
||||
//
|
||||
// SocketEnginePollable.swift
|
||||
// Socket.IO-Client-Swift
|
||||
//
|
||||
// Created by Erik Little on 1/15/16.
|
||||
//
|
||||
// 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.
|
||||
|
||||
import Foundation
|
||||
|
||||
/// Protocol that is used to implement socket.io polling support
|
||||
public protocol SocketEnginePollable : SocketEngineSpec {
|
||||
var invalidated: Bool { get }
|
||||
/// Holds strings waiting to be sent over polling.
|
||||
/// You shouldn't need to mess with this.
|
||||
var postWait: [String] { get set }
|
||||
var session: NSURLSession? { get }
|
||||
/// Because socket.io doesn't let you send two polling request at the same time
|
||||
/// we have to keep track if there's an outstanding poll
|
||||
var waitingForPoll: Bool { get set }
|
||||
/// Because socket.io doesn't let you send two post request at the same time
|
||||
/// we have to keep track if there's an outstanding post
|
||||
var waitingForPost: Bool { get set }
|
||||
|
||||
func doPoll()
|
||||
func sendPollMessage(message: String, withType type: SocketEnginePacketType, withData datas: [NSData])
|
||||
func stopPolling()
|
||||
}
|
||||
|
||||
// Default polling methods
|
||||
extension SocketEnginePollable {
|
||||
private func addHeaders(req: NSMutableURLRequest) {
|
||||
if cookies != nil {
|
||||
let headers = NSHTTPCookie.requestHeaderFieldsWithCookies(cookies!)
|
||||
req.allHTTPHeaderFields = headers
|
||||
}
|
||||
|
||||
if extraHeaders != nil {
|
||||
for (headerName, value) in extraHeaders! {
|
||||
req.setValue(value, forHTTPHeaderField: headerName)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func createRequestForPostWithPostWait() -> NSURLRequest {
|
||||
var postStr = ""
|
||||
|
||||
for packet in postWait {
|
||||
let len = packet.characters.count
|
||||
|
||||
postStr += "\(len):\(packet)"
|
||||
}
|
||||
|
||||
DefaultSocketLogger.Logger.log("Created POST string: %@", type: "SocketEnginePolling", args: postStr)
|
||||
|
||||
postWait.removeAll(keepCapacity: false)
|
||||
|
||||
let req = NSMutableURLRequest(URL: urlPollingWithSid)
|
||||
|
||||
addHeaders(req)
|
||||
|
||||
req.HTTPMethod = "POST"
|
||||
req.setValue("text/plain; charset=UTF-8", forHTTPHeaderField: "Content-Type")
|
||||
|
||||
let postData = postStr.dataUsingEncoding(NSUTF8StringEncoding,
|
||||
allowLossyConversion: false)!
|
||||
|
||||
req.HTTPBody = postData
|
||||
req.setValue(String(postData.length), forHTTPHeaderField: "Content-Length")
|
||||
|
||||
return req
|
||||
}
|
||||
|
||||
public func doPoll() {
|
||||
if websocket || waitingForPoll || !connected || closed {
|
||||
return
|
||||
}
|
||||
|
||||
waitingForPoll = true
|
||||
let req = NSMutableURLRequest(URL: urlPollingWithSid)
|
||||
|
||||
addHeaders(req)
|
||||
doLongPoll(req)
|
||||
}
|
||||
|
||||
func doRequest(req: NSURLRequest, withCallback callback: (NSData?, NSURLResponse?, NSError?) -> Void) {
|
||||
if !polling || closed || invalidated || fastUpgrade {
|
||||
DefaultSocketLogger.Logger.error("Tried to do polling request when not supposed to", type: "SocketEnginePolling")
|
||||
return
|
||||
}
|
||||
|
||||
DefaultSocketLogger.Logger.log("Doing polling request", type: "SocketEnginePolling")
|
||||
|
||||
session?.dataTaskWithRequest(req, completionHandler: callback).resume()
|
||||
}
|
||||
|
||||
func doLongPoll(req: NSURLRequest) {
|
||||
doRequest(req) {[weak self] data, res, err in
|
||||
guard let this = self where this.polling else { return }
|
||||
|
||||
if err != nil || data == nil {
|
||||
DefaultSocketLogger.Logger.error(err?.localizedDescription ?? "Error", type: "SocketEnginePolling")
|
||||
|
||||
if this.polling {
|
||||
this.didError(err?.localizedDescription ?? "Error")
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
DefaultSocketLogger.Logger.log("Got polling response", type: "SocketEnginePolling")
|
||||
|
||||
if let str = String(data: data!, encoding: NSUTF8StringEncoding) {
|
||||
dispatch_async(this.parseQueue) {
|
||||
this.parsePollingMessage(str)
|
||||
}
|
||||
}
|
||||
|
||||
this.waitingForPoll = false
|
||||
|
||||
if this.fastUpgrade {
|
||||
this.doFastUpgrade()
|
||||
} else if !this.closed && this.polling {
|
||||
this.doPoll()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func flushWaitingForPost() {
|
||||
if postWait.count == 0 || !connected {
|
||||
return
|
||||
} else if websocket {
|
||||
flushWaitingForPostToWebSocket()
|
||||
return
|
||||
}
|
||||
|
||||
let req = createRequestForPostWithPostWait()
|
||||
|
||||
waitingForPost = true
|
||||
|
||||
DefaultSocketLogger.Logger.log("POSTing", type: "SocketEnginePolling")
|
||||
|
||||
doRequest(req) {[weak self] data, res, err in
|
||||
guard let this = self else { return }
|
||||
|
||||
if err != nil {
|
||||
DefaultSocketLogger.Logger.error(err?.localizedDescription ?? "Error", type: "SocketEnginePolling")
|
||||
|
||||
if this.polling {
|
||||
this.didError(err?.localizedDescription ?? "Error")
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
this.waitingForPost = false
|
||||
|
||||
dispatch_async(this.emitQueue) {
|
||||
if !this.fastUpgrade {
|
||||
this.flushWaitingForPost()
|
||||
this.doPoll()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func parsePollingMessage(str: String) {
|
||||
guard str.characters.count != 1 else { return }
|
||||
|
||||
var reader = SocketStringReader(message: str)
|
||||
|
||||
while reader.hasNext {
|
||||
if let n = Int(reader.readUntilStringOccurence(":")) {
|
||||
let str = reader.read(n)
|
||||
|
||||
dispatch_async(handleQueue) {
|
||||
self.parseEngineMessage(str, fromPolling: true)
|
||||
}
|
||||
} else {
|
||||
dispatch_async(handleQueue) {
|
||||
self.parseEngineMessage(str, fromPolling: true)
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Send polling message.
|
||||
/// Only call on emitQueue
|
||||
public func sendPollMessage(message: String, withType type: SocketEnginePacketType, withData datas: [NSData]) {
|
||||
DefaultSocketLogger.Logger.log("Sending poll: %@ as type: %@", type: "SocketEnginePolling", args: message, type.rawValue)
|
||||
let fixedMessage: String
|
||||
|
||||
if doubleEncodeUTF8 {
|
||||
fixedMessage = doubleEncodeUTF8(message)
|
||||
} else {
|
||||
fixedMessage = message
|
||||
}
|
||||
|
||||
let strMsg = "\(type.rawValue)\(fixedMessage)"
|
||||
|
||||
postWait.append(strMsg)
|
||||
|
||||
for data in datas {
|
||||
if case let .Right(bin) = createBinaryDataForSend(data) {
|
||||
postWait.append(bin)
|
||||
}
|
||||
}
|
||||
|
||||
if !waitingForPost {
|
||||
flushWaitingForPost()
|
||||
}
|
||||
}
|
||||
|
||||
public func stopPolling() {
|
||||
waitingForPoll = false
|
||||
waitingForPost = false
|
||||
session?.finishTasksAndInvalidate()
|
||||
}
|
||||
}
|
||||
@ -1,115 +0,0 @@
|
||||
//
|
||||
// SocketEngineSpec.swift
|
||||
// Socket.IO-Client-Swift
|
||||
//
|
||||
// Created by Erik Little on 10/7/15.
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
@objc public protocol SocketEngineSpec {
|
||||
weak var client: SocketEngineClient? { get set }
|
||||
var closed: Bool { get }
|
||||
var connected: Bool { get }
|
||||
var connectParams: [String: AnyObject]? { get set }
|
||||
var doubleEncodeUTF8: Bool { get }
|
||||
var cookies: [NSHTTPCookie]? { get }
|
||||
var extraHeaders: [String: String]? { get }
|
||||
var fastUpgrade: Bool { get }
|
||||
var forcePolling: Bool { get }
|
||||
var forceWebsockets: Bool { get }
|
||||
var parseQueue: dispatch_queue_t! { get }
|
||||
var polling: Bool { get }
|
||||
var probing: Bool { get }
|
||||
var emitQueue: dispatch_queue_t! { get }
|
||||
var handleQueue: dispatch_queue_t! { get }
|
||||
var sid: String { get }
|
||||
var socketPath: String { get }
|
||||
var urlPolling: NSURL { get }
|
||||
var urlWebSocket: NSURL { get }
|
||||
var websocket: Bool { get }
|
||||
var ws: WebSocket? { get }
|
||||
|
||||
init(client: SocketEngineClient, url: NSURL, options: NSDictionary?)
|
||||
|
||||
func connect()
|
||||
func didError(error: String)
|
||||
func disconnect(reason: String)
|
||||
func doFastUpgrade()
|
||||
func flushWaitingForPostToWebSocket()
|
||||
func parseEngineData(data: NSData)
|
||||
func parseEngineMessage(message: String, fromPolling: Bool)
|
||||
func write(msg: String, withType type: SocketEnginePacketType, withData data: [NSData])
|
||||
}
|
||||
|
||||
extension SocketEngineSpec {
|
||||
var urlPollingWithSid: NSURL {
|
||||
let com = NSURLComponents(URL: urlPolling, resolvingAgainstBaseURL: false)!
|
||||
com.percentEncodedQuery = com.percentEncodedQuery! + "&sid=\(sid.urlEncode()!)"
|
||||
|
||||
return com.URL!
|
||||
}
|
||||
|
||||
var urlWebSocketWithSid: NSURL {
|
||||
let com = NSURLComponents(URL: urlWebSocket, resolvingAgainstBaseURL: false)!
|
||||
com.percentEncodedQuery = com.percentEncodedQuery! + (sid == "" ? "" : "&sid=\(sid.urlEncode()!)")
|
||||
|
||||
return com.URL!
|
||||
}
|
||||
|
||||
func createBinaryDataForSend(data: NSData) -> Either<NSData, String> {
|
||||
if websocket {
|
||||
var byteArray = [UInt8](count: 1, repeatedValue: 0x4)
|
||||
let mutData = NSMutableData(bytes: &byteArray, length: 1)
|
||||
|
||||
mutData.appendData(data)
|
||||
|
||||
return .Left(mutData)
|
||||
} else {
|
||||
let str = "b4" + data.base64EncodedStringWithOptions(NSDataBase64EncodingOptions(rawValue: 0))
|
||||
|
||||
return .Right(str)
|
||||
}
|
||||
}
|
||||
|
||||
func doubleEncodeUTF8(string: String) -> String {
|
||||
if let latin1 = string.dataUsingEncoding(NSUTF8StringEncoding),
|
||||
utf8 = NSString(data: latin1, encoding: NSISOLatin1StringEncoding) {
|
||||
return utf8 as String
|
||||
} else {
|
||||
return string
|
||||
}
|
||||
}
|
||||
|
||||
func fixDoubleUTF8(string: String) -> String {
|
||||
if let utf8 = string.dataUsingEncoding(NSISOLatin1StringEncoding),
|
||||
latin1 = NSString(data: utf8, encoding: NSUTF8StringEncoding) {
|
||||
return latin1 as String
|
||||
} else {
|
||||
return string
|
||||
}
|
||||
}
|
||||
|
||||
/// Send an engine message (4)
|
||||
func send(msg: String, withData datas: [NSData]) {
|
||||
write(msg, withType: .Message, withData: datas)
|
||||
}
|
||||
}
|
||||
@ -1,62 +0,0 @@
|
||||
//
|
||||
// SocketEngineWebsocket.swift
|
||||
// Socket.IO-Client-Swift
|
||||
//
|
||||
// Created by Erik Little on 1/15/16.
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
/// Protocol that is used to implement socket.io WebSocket support
|
||||
public protocol SocketEngineWebsocket : SocketEngineSpec, WebSocketDelegate {
|
||||
func sendWebSocketMessage(str: String, withType type: SocketEnginePacketType, withData datas: [NSData])
|
||||
}
|
||||
|
||||
// WebSocket methods
|
||||
extension SocketEngineWebsocket {
|
||||
func probeWebSocket() {
|
||||
if ws?.isConnected ?? false {
|
||||
sendWebSocketMessage("probe", withType: .Ping, withData: [])
|
||||
}
|
||||
}
|
||||
|
||||
/// Send message on WebSockets
|
||||
/// Only call on emitQueue
|
||||
public func sendWebSocketMessage(str: String, withType type: SocketEnginePacketType, withData datas: [NSData]) {
|
||||
DefaultSocketLogger.Logger.log("Sending ws: %@ as type: %@", type: "SocketEngine", args: str, type.rawValue)
|
||||
|
||||
ws?.writeString("\(type.rawValue)\(str)")
|
||||
|
||||
for data in datas {
|
||||
if case let .Left(bin) = createBinaryDataForSend(data) {
|
||||
ws?.writeData(bin)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public func websocketDidReceiveMessage(socket: WebSocket, text: String) {
|
||||
parseEngineMessage(text, fromPolling: false)
|
||||
}
|
||||
|
||||
public func websocketDidReceiveData(socket: WebSocket, data: NSData) {
|
||||
parseEngineData(data)
|
||||
}
|
||||
}
|
||||
146
Source/SocketIO/Ack/SocketAckEmitter.swift
Normal file
146
Source/SocketIO/Ack/SocketAckEmitter.swift
Normal file
@ -0,0 +1,146 @@
|
||||
//
|
||||
// SocketAckEmitter.swift
|
||||
// Socket.IO-Client-Swift
|
||||
//
|
||||
// Created by Erik Little on 9/16/15.
|
||||
//
|
||||
// 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.
|
||||
|
||||
import Dispatch
|
||||
import Foundation
|
||||
|
||||
/// A class that represents a waiting ack call.
|
||||
///
|
||||
/// **NOTE**: You should not store this beyond the life of the event handler.
|
||||
public final class SocketAckEmitter: NSObject {
|
||||
private unowned let socket: SocketIOClient
|
||||
private let ackNum: Int
|
||||
|
||||
/// A view into this emitter where emits do not check for binary data.
|
||||
///
|
||||
/// Usage:
|
||||
///
|
||||
/// ```swift
|
||||
/// ack.rawEmitView.with(myObject)
|
||||
/// ```
|
||||
///
|
||||
/// **NOTE**: It is not safe to hold on to this view beyond the life of the socket.
|
||||
@objc
|
||||
public private(set) lazy var rawEmitView = SocketRawAckView(socket: socket, ackNum: ackNum)
|
||||
|
||||
// MARK: Properties
|
||||
|
||||
/// If true, this handler is expecting to be acked. Call `with(_: SocketData...)` to ack.
|
||||
public var expected: Bool {
|
||||
return ackNum != -1
|
||||
}
|
||||
|
||||
// MARK: Initializers
|
||||
|
||||
/// Creates a new `SocketAckEmitter`.
|
||||
///
|
||||
/// - parameter socket: The socket for this emitter.
|
||||
/// - parameter ackNum: The ack number for this emitter.
|
||||
public init(socket: SocketIOClient, ackNum: Int) {
|
||||
self.socket = socket
|
||||
self.ackNum = ackNum
|
||||
}
|
||||
|
||||
// MARK: Methods
|
||||
|
||||
/// Call to ack receiving this event.
|
||||
///
|
||||
/// If an error occurs trying to transform `items` into their socket representation, a `SocketClientEvent.error`
|
||||
/// will be emitted. The structure of the error data is `[ackNum, items, theError]`
|
||||
///
|
||||
/// - parameter items: A variable number of items to send when acking.
|
||||
public func with(_ items: SocketData...) {
|
||||
guard ackNum != -1 else { return }
|
||||
|
||||
do {
|
||||
socket.emitAck(ackNum, with: try items.map({ try $0.socketRepresentation() }))
|
||||
} catch {
|
||||
socket.handleClientEvent(.error, data: [ackNum, items, error])
|
||||
}
|
||||
}
|
||||
|
||||
/// Call to ack receiving this event.
|
||||
///
|
||||
/// - parameter items: An array of items to send when acking. Use `[]` to send nothing.
|
||||
@objc
|
||||
public func with(_ items: [Any]) {
|
||||
guard ackNum != -1 else { return }
|
||||
|
||||
socket.emitAck(ackNum, with: items)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// A class that represents an emit that will request an ack that has not yet been sent.
|
||||
/// Call `timingOut(after:callback:)` to complete the emit
|
||||
/// Example:
|
||||
///
|
||||
/// ```swift
|
||||
/// socket.emitWithAck("myEvent").timingOut(after: 1) {data in
|
||||
/// ...
|
||||
/// }
|
||||
/// ```
|
||||
public final class OnAckCallback: NSObject {
|
||||
private let ackNumber: Int
|
||||
private let binary: Bool
|
||||
private let items: [Any]
|
||||
|
||||
private weak var socket: SocketIOClient?
|
||||
|
||||
init(ackNumber: Int, items: [Any], socket: SocketIOClient, binary: Bool = true) {
|
||||
self.ackNumber = ackNumber
|
||||
self.items = items
|
||||
self.socket = socket
|
||||
self.binary = binary
|
||||
}
|
||||
|
||||
/// :nodoc:
|
||||
deinit {
|
||||
DefaultSocketLogger.Logger.log("OnAckCallback for \(ackNumber) being released", type: "OnAckCallback")
|
||||
}
|
||||
|
||||
// MARK: Methods
|
||||
|
||||
/// Completes an emitWithAck. If this isn't called, the emit never happens.
|
||||
///
|
||||
/// - parameter seconds: The number of seconds before this emit times out if an ack hasn't been received.
|
||||
/// - parameter callback: The callback called when an ack is received, or when a timeout happens.
|
||||
/// To check for timeout, use `SocketAckStatus`'s `noAck` case.
|
||||
@objc
|
||||
public func timingOut(after seconds: Double, callback: @escaping AckCallback) {
|
||||
guard let socket = self.socket, ackNumber != -1 else { return }
|
||||
|
||||
socket.ackHandlers.addAck(ackNumber, callback: callback)
|
||||
socket.emit(items, ack: ackNumber, binary: binary)
|
||||
|
||||
guard seconds != 0 else { return }
|
||||
|
||||
socket.manager?.handleQueue.asyncAfter(deadline: DispatchTime.now() + seconds) {[weak socket] in
|
||||
guard let socket = socket else { return }
|
||||
|
||||
socket.ackHandlers.timeoutAck(self.ackNumber)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -22,53 +22,67 @@
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
import Dispatch
|
||||
import Foundation
|
||||
|
||||
private struct SocketAck : Hashable, Equatable {
|
||||
/// The status of an ack.
|
||||
public enum SocketAckStatus : String {
|
||||
// MARK: Cases
|
||||
|
||||
/// The ack timed out.
|
||||
case noAck = "NO ACK"
|
||||
|
||||
/// Tests whether a string is equal to a given SocketAckStatus
|
||||
public static func == (lhs: String, rhs: SocketAckStatus) -> Bool {
|
||||
return lhs == rhs.rawValue
|
||||
}
|
||||
|
||||
/// Tests whether a string is equal to a given SocketAckStatus
|
||||
public static func == (lhs: SocketAckStatus, rhs: String) -> Bool {
|
||||
return rhs == lhs
|
||||
}
|
||||
}
|
||||
|
||||
private struct SocketAck : Hashable {
|
||||
let ack: Int
|
||||
var callback: AckCallback!
|
||||
var hashValue: Int {
|
||||
return ack.hashValue
|
||||
}
|
||||
|
||||
|
||||
init(ack: Int) {
|
||||
self.ack = ack
|
||||
}
|
||||
|
||||
init(ack: Int, callback: AckCallback) {
|
||||
|
||||
init(ack: Int, callback: @escaping AckCallback) {
|
||||
self.ack = ack
|
||||
self.callback = callback
|
||||
}
|
||||
|
||||
func hash(into hasher: inout Hasher) {
|
||||
ack.hash(into: &hasher)
|
||||
}
|
||||
|
||||
fileprivate static func <(lhs: SocketAck, rhs: SocketAck) -> Bool {
|
||||
return lhs.ack < rhs.ack
|
||||
}
|
||||
|
||||
fileprivate static func ==(lhs: SocketAck, rhs: SocketAck) -> Bool {
|
||||
return lhs.ack == rhs.ack
|
||||
}
|
||||
}
|
||||
|
||||
private func <(lhs: SocketAck, rhs: SocketAck) -> Bool {
|
||||
return lhs.ack < rhs.ack
|
||||
}
|
||||
|
||||
private func ==(lhs: SocketAck, rhs: SocketAck) -> Bool {
|
||||
return lhs.ack == rhs.ack
|
||||
}
|
||||
|
||||
struct SocketAckManager {
|
||||
class SocketAckManager {
|
||||
private var acks = Set<SocketAck>(minimumCapacity: 1)
|
||||
|
||||
mutating func addAck(ack: Int, callback: AckCallback) {
|
||||
|
||||
func addAck(_ ack: Int, callback: @escaping AckCallback) {
|
||||
acks.insert(SocketAck(ack: ack, callback: callback))
|
||||
}
|
||||
|
||||
mutating func executeAck(ack: Int, items: [AnyObject]) {
|
||||
let callback = acks.remove(SocketAck(ack: ack))
|
||||
|
||||
dispatch_async(dispatch_get_main_queue()) {
|
||||
callback?.callback(items)
|
||||
}
|
||||
/// Should be called on handle queue
|
||||
func executeAck(_ ack: Int, with items: [Any]) {
|
||||
acks.remove(SocketAck(ack: ack))?.callback(items)
|
||||
}
|
||||
|
||||
mutating func timeoutAck(ack: Int) {
|
||||
let callback = acks.remove(SocketAck(ack: ack))
|
||||
|
||||
dispatch_async(dispatch_get_main_queue()) {
|
||||
callback?.callback(["NO ACK"])
|
||||
}
|
||||
|
||||
/// Should be called on handle queue
|
||||
func timeoutAck(_ ack: Int) {
|
||||
acks.remove(SocketAck(ack: ack))?.callback?([SocketAckStatus.noAck.rawValue])
|
||||
}
|
||||
}
|
||||
@ -24,14 +24,24 @@
|
||||
|
||||
import Foundation
|
||||
|
||||
/// Represents some event that was received.
|
||||
public final class SocketAnyEvent : NSObject {
|
||||
// MARK: Properties
|
||||
|
||||
/// The event name.
|
||||
@objc
|
||||
public let event: String
|
||||
public let items: NSArray?
|
||||
|
||||
/// The data items for this event.
|
||||
@objc
|
||||
public let items: [Any]?
|
||||
|
||||
/// The description of this event.
|
||||
override public var description: String {
|
||||
return "SocketAnyEvent: Event: \(event) items: \(items ?? nil)"
|
||||
return "SocketAnyEvent: Event: \(event) items: \(String(describing: items))"
|
||||
}
|
||||
|
||||
init(event: String, items: NSArray?) {
|
||||
|
||||
init(event: String, items: [Any]?) {
|
||||
self.event = event
|
||||
self.items = items
|
||||
}
|
||||
@ -24,12 +24,27 @@
|
||||
|
||||
import Foundation
|
||||
|
||||
struct SocketEventHandler {
|
||||
let event: String
|
||||
let id: NSUUID
|
||||
let callback: NormalCallback
|
||||
|
||||
func executeCallback(items: [AnyObject], withAck ack: Int, withSocket socket: SocketIOClient) {
|
||||
/// A wrapper around a handler.
|
||||
public struct SocketEventHandler {
|
||||
// MARK: Properties
|
||||
|
||||
/// The event for this handler.
|
||||
public let event: String
|
||||
|
||||
/// A unique identifier for this handler.
|
||||
public let id: UUID
|
||||
|
||||
/// The actual handler function.
|
||||
public let callback: NormalCallback
|
||||
|
||||
// MARK: Methods
|
||||
|
||||
/// Causes this handler to be executed.
|
||||
///
|
||||
/// - parameter with: The data that this handler should be called with.
|
||||
/// - parameter withAck: The ack number that this event expects. Pass -1 to say this event doesn't expect an ack.
|
||||
/// - parameter withSocket: The socket that is calling this event.
|
||||
public func executeCallback(with items: [Any], withAck ack: Int, withSocket socket: SocketIOClient) {
|
||||
callback(items, SocketAckEmitter(socket: socket, ackNum: ack))
|
||||
}
|
||||
}
|
||||
549
Source/SocketIO/Client/SocketIOClient.swift
Normal file
549
Source/SocketIO/Client/SocketIOClient.swift
Normal file
@ -0,0 +1,549 @@
|
||||
//
|
||||
// SocketIOClient.swift
|
||||
// Socket.IO-Client-Swift
|
||||
//
|
||||
// Created by Erik Little on 11/23/14.
|
||||
//
|
||||
// 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.
|
||||
|
||||
import Dispatch
|
||||
import Foundation
|
||||
|
||||
/// Represents a socket.io-client.
|
||||
///
|
||||
/// Clients are created through a `SocketManager`, which owns the `SocketEngineSpec` that controls the connection to the server.
|
||||
///
|
||||
/// For example:
|
||||
///
|
||||
/// ```swift
|
||||
/// // Create a socket for the /swift namespace
|
||||
/// let socket = manager.socket(forNamespace: "/swift")
|
||||
///
|
||||
/// // Add some handlers and connect
|
||||
/// ```
|
||||
///
|
||||
/// **NOTE**: The client is not thread/queue safe, all interaction with the socket should be done on the `manager.handleQueue`
|
||||
///
|
||||
open class SocketIOClient: NSObject, SocketIOClientSpec {
|
||||
// MARK: Properties
|
||||
|
||||
/// The namespace that this socket is currently connected to.
|
||||
///
|
||||
/// **Must** start with a `/`.
|
||||
public let nsp: String
|
||||
|
||||
/// A handler that will be called on any event.
|
||||
public private(set) var anyHandler: ((SocketAnyEvent) -> ())?
|
||||
|
||||
/// The array of handlers for this socket.
|
||||
public private(set) var handlers = [SocketEventHandler]()
|
||||
|
||||
/// The manager for this socket.
|
||||
public private(set) weak var manager: SocketManagerSpec?
|
||||
|
||||
/// A view into this socket where emits do not check for binary data.
|
||||
///
|
||||
/// Usage:
|
||||
///
|
||||
/// ```swift
|
||||
/// socket.rawEmitView.emit("myEvent", myObject)
|
||||
/// ```
|
||||
///
|
||||
/// **NOTE**: It is not safe to hold on to this view beyond the life of the socket.
|
||||
public private(set) lazy var rawEmitView = SocketRawView(socket: self)
|
||||
|
||||
/// The status of this client.
|
||||
public private(set) var status = SocketIOStatus.notConnected {
|
||||
didSet {
|
||||
handleClientEvent(.statusChange, data: [status, status.rawValue])
|
||||
}
|
||||
}
|
||||
|
||||
/// The id of this socket.io connect. This is different from the sid of the engine.io connection.
|
||||
public private(set) var sid: String?
|
||||
|
||||
let ackHandlers = SocketAckManager()
|
||||
var connectPayload: [String: Any]?
|
||||
|
||||
private(set) var currentAck = -1
|
||||
|
||||
private lazy var logType = "SocketIOClient{\(nsp)}"
|
||||
|
||||
// MARK: Initializers
|
||||
|
||||
/// Type safe way to create a new SocketIOClient. `opts` can be omitted.
|
||||
///
|
||||
/// - parameter manager: The manager for this socket.
|
||||
/// - parameter nsp: The namespace of the socket.
|
||||
public init(manager: SocketManagerSpec, nsp: String) {
|
||||
self.manager = manager
|
||||
self.nsp = nsp
|
||||
|
||||
super.init()
|
||||
}
|
||||
|
||||
/// :nodoc:
|
||||
deinit {
|
||||
DefaultSocketLogger.Logger.log("Client is being released", type: logType)
|
||||
}
|
||||
|
||||
// MARK: Methods
|
||||
|
||||
/// Connect to the server. The same as calling `connect(timeoutAfter:withHandler:)` with a timeout of 0.
|
||||
///
|
||||
/// Only call after adding your event listeners, unless you know what you're doing.
|
||||
///
|
||||
/// - parameter withPayload: An optional payload sent on connect
|
||||
open func connect(withPayload payload: [String: Any]? = nil) {
|
||||
connect(withPayload: payload, timeoutAfter: 0, withHandler: nil)
|
||||
}
|
||||
|
||||
/// Connect to the server. If we aren't connected after `timeoutAfter` seconds, then `withHandler` is called.
|
||||
///
|
||||
/// Only call after adding your event listeners, unless you know what you're doing.
|
||||
///
|
||||
/// - parameter withPayload: An optional payload sent on connect
|
||||
/// - parameter timeoutAfter: The number of seconds after which if we are not connected we assume the connection
|
||||
/// has failed. Pass 0 to never timeout.
|
||||
/// - parameter handler: The handler to call when the client fails to connect.
|
||||
open func connect(withPayload payload: [String: Any]? = nil, timeoutAfter: Double, withHandler handler: (() -> ())?) {
|
||||
assert(timeoutAfter >= 0, "Invalid timeout: \(timeoutAfter)")
|
||||
|
||||
guard let manager = self.manager, status != .connected else {
|
||||
DefaultSocketLogger.Logger.log("Tried connecting on an already connected socket", type: logType)
|
||||
return
|
||||
}
|
||||
|
||||
status = .connecting
|
||||
|
||||
joinNamespace(withPayload: payload)
|
||||
|
||||
switch manager.version {
|
||||
case .three:
|
||||
break
|
||||
case .two where manager.status == .connected && nsp == "/":
|
||||
// We might not get a connect event for the default nsp, fire immediately
|
||||
didConnect(toNamespace: nsp, payload: nil)
|
||||
|
||||
return
|
||||
case _:
|
||||
break
|
||||
}
|
||||
|
||||
guard timeoutAfter != 0 else { return }
|
||||
|
||||
manager.handleQueue.asyncAfter(deadline: DispatchTime.now() + timeoutAfter) {[weak self] in
|
||||
guard let this = self, this.status == .connecting || this.status == .notConnected else { return }
|
||||
DefaultSocketLogger.Logger.log("Timeout: Socket not connected, so setting to disconnected", type: this.logType)
|
||||
|
||||
this.status = .disconnected
|
||||
this.leaveNamespace()
|
||||
|
||||
handler?()
|
||||
}
|
||||
}
|
||||
|
||||
func createOnAck(_ items: [Any], binary: Bool = true) -> OnAckCallback {
|
||||
currentAck += 1
|
||||
|
||||
return OnAckCallback(ackNumber: currentAck, items: items, socket: self)
|
||||
}
|
||||
|
||||
/// Called when the client connects to a namespace. If the client was created with a namespace upfront,
|
||||
/// then this is only called when the client connects to that namespace.
|
||||
///
|
||||
/// - parameter toNamespace: The namespace that was connected to.
|
||||
open func didConnect(toNamespace namespace: String, payload: [String: Any]?) {
|
||||
guard status != .connected else { return }
|
||||
|
||||
DefaultSocketLogger.Logger.log("Socket connected", type: logType)
|
||||
|
||||
status = .connected
|
||||
sid = payload?["sid"] as? String
|
||||
|
||||
handleClientEvent(.connect, data: payload == nil ? [namespace] : [namespace, payload!])
|
||||
}
|
||||
|
||||
/// Called when the client has disconnected from socket.io.
|
||||
///
|
||||
/// - parameter reason: The reason for the disconnection.
|
||||
open func didDisconnect(reason: String) {
|
||||
guard status != .disconnected else { return }
|
||||
|
||||
DefaultSocketLogger.Logger.log("Disconnected: \(reason)", type: logType)
|
||||
|
||||
status = .disconnected
|
||||
sid = ""
|
||||
|
||||
handleClientEvent(.disconnect, data: [reason])
|
||||
}
|
||||
|
||||
/// Disconnects the socket.
|
||||
///
|
||||
/// This will cause the socket to leave the namespace it is associated to, as well as remove itself from the
|
||||
/// `manager`.
|
||||
open func disconnect() {
|
||||
DefaultSocketLogger.Logger.log("Closing socket", type: logType)
|
||||
|
||||
leaveNamespace()
|
||||
}
|
||||
|
||||
/// Send an event to the server, with optional data items and optional write completion handler.
|
||||
///
|
||||
/// If an error occurs trying to transform `items` into their socket representation, a `SocketClientEvent.error`
|
||||
/// will be emitted. The structure of the error data is `[eventName, items, theError]`
|
||||
///
|
||||
/// - parameter event: The event to send.
|
||||
/// - parameter items: The items to send with this event. May be left out.
|
||||
/// - parameter completion: Callback called on transport write completion.
|
||||
open func emit(_ event: String, _ items: SocketData..., completion: (() -> ())? = nil) {
|
||||
emit(event, with: items, completion: completion)
|
||||
}
|
||||
|
||||
/// Send an event to the server, with optional data items and optional write completion handler.
|
||||
///
|
||||
/// If an error occurs trying to transform `items` into their socket representation, a `SocketClientEvent.error`
|
||||
/// will be emitted. The structure of the error data is `[eventName, items, theError]`
|
||||
///
|
||||
/// - parameter event: The event to send.
|
||||
/// - parameter items: The items to send with this event. May be left out.
|
||||
/// - parameter completion: Callback called on transport write completion.
|
||||
open func emit(_ event: String, with items: [SocketData], completion: (() -> ())?) {
|
||||
|
||||
do {
|
||||
emit([event] + (try items.map({ try $0.socketRepresentation() })), completion: completion)
|
||||
} catch {
|
||||
DefaultSocketLogger.Logger.error("Error creating socketRepresentation for emit: \(event), \(items)",
|
||||
type: logType)
|
||||
|
||||
handleClientEvent(.error, data: [event, items, error])
|
||||
}
|
||||
}
|
||||
|
||||
/// Sends a message to the server, requesting an ack.
|
||||
///
|
||||
/// **NOTE**: It is up to the server send an ack back, just calling this method does not mean the server will ack.
|
||||
/// Check that your server's api will ack the event being sent.
|
||||
///
|
||||
/// If an error occurs trying to transform `items` into their socket representation, a `SocketClientEvent.error`
|
||||
/// will be emitted. The structure of the error data is `[eventName, items, theError]`
|
||||
///
|
||||
/// Example:
|
||||
///
|
||||
/// ```swift
|
||||
/// socket.emitWithAck("myEvent", 1).timingOut(after: 1) {data in
|
||||
/// ...
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// - parameter event: The event to send.
|
||||
/// - parameter items: The items to send with this event. May be left out.
|
||||
/// - returns: An `OnAckCallback`. You must call the `timingOut(after:)` method before the event will be sent.
|
||||
open func emitWithAck(_ event: String, _ items: SocketData...) -> OnAckCallback {
|
||||
emitWithAck(event, with: items)
|
||||
}
|
||||
|
||||
/// Sends a message to the server, requesting an ack.
|
||||
///
|
||||
/// **NOTE**: It is up to the server send an ack back, just calling this method does not mean the server will ack.
|
||||
/// Check that your server's api will ack the event being sent.
|
||||
///
|
||||
/// If an error occurs trying to transform `items` into their socket representation, a `SocketClientEvent.error`
|
||||
/// will be emitted. The structure of the error data is `[eventName, items, theError]`
|
||||
///
|
||||
/// Example:
|
||||
///
|
||||
/// ```swift
|
||||
/// socket.emitWithAck("myEvent", 1).timingOut(after: 1) {data in
|
||||
/// ...
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// - parameter event: The event to send.
|
||||
/// - parameter items: The items to send with this event. May be left out.
|
||||
/// - returns: An `OnAckCallback`. You must call the `timingOut(after:)` method before the event will be sent.
|
||||
open func emitWithAck(_ event: String, with items: [SocketData]) -> OnAckCallback {
|
||||
|
||||
do {
|
||||
return createOnAck([event] + (try items.map({ try $0.socketRepresentation() })))
|
||||
} catch {
|
||||
DefaultSocketLogger.Logger.error("Error creating socketRepresentation for emit: \(event), \(items)",
|
||||
type: logType)
|
||||
|
||||
handleClientEvent(.error, data: [event, items, error])
|
||||
|
||||
return OnAckCallback(ackNumber: -1, items: [], socket: self)
|
||||
}
|
||||
}
|
||||
|
||||
func emit(_ data: [Any],
|
||||
ack: Int? = nil,
|
||||
binary: Bool = true,
|
||||
isAck: Bool = false,
|
||||
completion: (() -> ())? = nil
|
||||
) {
|
||||
// wrap the completion handler so it always runs async via handlerQueue
|
||||
let wrappedCompletion: (() -> ())? = (completion == nil) ? nil : {[weak self] in
|
||||
guard let this = self else { return }
|
||||
this.manager?.handleQueue.async {
|
||||
completion!()
|
||||
}
|
||||
}
|
||||
|
||||
guard status == .connected else {
|
||||
wrappedCompletion?()
|
||||
handleClientEvent(.error, data: ["Tried emitting when not connected"])
|
||||
return
|
||||
}
|
||||
|
||||
let packet = SocketPacket.packetFromEmit(data, id: ack ?? -1, nsp: nsp, ack: isAck, checkForBinary: binary)
|
||||
let str = packet.packetString
|
||||
|
||||
DefaultSocketLogger.Logger.log("Emitting: \(str), Ack: \(isAck)", type: logType)
|
||||
|
||||
manager?.engine?.send(str, withData: packet.binary, completion: wrappedCompletion)
|
||||
}
|
||||
|
||||
/// Call when you wish to tell the server that you've received the event for `ack`.
|
||||
///
|
||||
/// **You shouldn't need to call this directly.** Instead use an `SocketAckEmitter` that comes in an event callback.
|
||||
///
|
||||
/// - parameter ack: The ack number.
|
||||
/// - parameter with: The data for this ack.
|
||||
open func emitAck(_ ack: Int, with items: [Any]) {
|
||||
emit(items, ack: ack, binary: true, isAck: true)
|
||||
}
|
||||
|
||||
/// Called when socket.io has acked one of our emits. Causes the corresponding ack callback to be called.
|
||||
///
|
||||
/// - parameter ack: The number for this ack.
|
||||
/// - parameter data: The data sent back with this ack.
|
||||
open func handleAck(_ ack: Int, data: [Any]) {
|
||||
guard status == .connected else { return }
|
||||
|
||||
DefaultSocketLogger.Logger.log("Handling ack: \(ack) with data: \(data)", type: logType)
|
||||
|
||||
ackHandlers.executeAck(ack, with: data)
|
||||
}
|
||||
|
||||
/// Called on socket.io specific events.
|
||||
///
|
||||
/// - parameter event: The `SocketClientEvent`.
|
||||
/// - parameter data: The data for this event.
|
||||
open func handleClientEvent(_ event: SocketClientEvent, data: [Any]) {
|
||||
handleEvent(event.rawValue, data: data, isInternalMessage: true)
|
||||
}
|
||||
|
||||
/// Called when we get an event from socket.io.
|
||||
///
|
||||
/// - parameter event: The name of the event.
|
||||
/// - parameter data: The data that was sent with this event.
|
||||
/// - parameter isInternalMessage: Whether this event was sent internally. If `true` it is always sent to handlers.
|
||||
/// - parameter ack: If > 0 then this event expects to get an ack back from the client.
|
||||
open func handleEvent(_ event: String, data: [Any], isInternalMessage: Bool, withAck ack: Int = -1) {
|
||||
guard status == .connected || isInternalMessage else { return }
|
||||
|
||||
DefaultSocketLogger.Logger.log("Handling event: \(event) with data: \(data)", type: logType)
|
||||
|
||||
anyHandler?(SocketAnyEvent(event: event, items: data))
|
||||
|
||||
for handler in handlers where handler.event == event {
|
||||
handler.executeCallback(with: data, withAck: ack, withSocket: self)
|
||||
}
|
||||
}
|
||||
|
||||
/// Causes a client to handle a socket.io packet. The namespace for the packet must match the namespace of the
|
||||
/// socket.
|
||||
///
|
||||
/// - parameter packet: The packet to handle.
|
||||
open func handlePacket(_ packet: SocketPacket) {
|
||||
guard packet.nsp == nsp else { return }
|
||||
|
||||
switch packet.type {
|
||||
case .event, .binaryEvent:
|
||||
handleEvent(packet.event, data: packet.args, isInternalMessage: false, withAck: packet.id)
|
||||
case .ack, .binaryAck:
|
||||
handleAck(packet.id, data: packet.data)
|
||||
case .connect:
|
||||
didConnect(toNamespace: nsp, payload: packet.data.isEmpty ? nil : packet.data[0] as? [String: Any])
|
||||
case .disconnect:
|
||||
didDisconnect(reason: "Got Disconnect")
|
||||
case .error:
|
||||
handleEvent("error", data: packet.data, isInternalMessage: true, withAck: packet.id)
|
||||
}
|
||||
}
|
||||
|
||||
/// Call when you wish to leave a namespace and disconnect this socket.
|
||||
open func leaveNamespace() {
|
||||
manager?.disconnectSocket(self)
|
||||
}
|
||||
|
||||
/// Joins `nsp`. You shouldn't need to call this directly, instead call `connect`.
|
||||
///
|
||||
/// - parameter withPayload: An optional payload sent on connect
|
||||
open func joinNamespace(withPayload payload: [String: Any]? = nil) {
|
||||
DefaultSocketLogger.Logger.log("Joining namespace \(nsp)", type: logType)
|
||||
|
||||
connectPayload = payload
|
||||
|
||||
manager?.connectSocket(self, withPayload: connectPayload)
|
||||
}
|
||||
|
||||
/// Removes handler(s) for a client event.
|
||||
///
|
||||
/// If you wish to remove a client event handler, call the `off(id:)` with the UUID received from its `on` call.
|
||||
///
|
||||
/// - parameter clientEvent: The event to remove handlers for.
|
||||
open func off(clientEvent event: SocketClientEvent) {
|
||||
off(event.rawValue)
|
||||
}
|
||||
|
||||
/// Removes handler(s) based on an event name.
|
||||
///
|
||||
/// If you wish to remove a specific event, call the `off(id:)` with the UUID received from its `on` call.
|
||||
///
|
||||
/// - parameter event: The event to remove handlers for.
|
||||
open func off(_ event: String) {
|
||||
DefaultSocketLogger.Logger.log("Removing handler for event: \(event)", type: logType)
|
||||
|
||||
handlers = handlers.filter({ $0.event != event })
|
||||
}
|
||||
|
||||
/// Removes a handler with the specified UUID gotten from an `on` or `once`
|
||||
///
|
||||
/// If you want to remove all events for an event, call the off `off(_:)` method with the event name.
|
||||
///
|
||||
/// - parameter id: The UUID of the handler you wish to remove.
|
||||
open func off(id: UUID) {
|
||||
DefaultSocketLogger.Logger.log("Removing handler with id: \(id)", type: logType)
|
||||
|
||||
handlers = handlers.filter({ $0.id != id })
|
||||
}
|
||||
|
||||
/// Adds a handler for an event.
|
||||
///
|
||||
/// - parameter event: The event name for this handler.
|
||||
/// - parameter callback: The callback that will execute when this event is received.
|
||||
/// - returns: A unique id for the handler that can be used to remove it.
|
||||
@discardableResult
|
||||
open func on(_ event: String, callback: @escaping NormalCallback) -> UUID {
|
||||
DefaultSocketLogger.Logger.log("Adding handler for event: \(event)", type: logType)
|
||||
|
||||
let handler = SocketEventHandler(event: event, id: UUID(), callback: callback)
|
||||
handlers.append(handler)
|
||||
|
||||
return handler.id
|
||||
}
|
||||
|
||||
/// Adds a handler for a client event.
|
||||
///
|
||||
/// Example:
|
||||
///
|
||||
/// ```swift
|
||||
/// socket.on(clientEvent: .connect) {data, ack in
|
||||
/// ...
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// - parameter event: The event for this handler.
|
||||
/// - parameter callback: The callback that will execute when this event is received.
|
||||
/// - returns: A unique id for the handler that can be used to remove it.
|
||||
@discardableResult
|
||||
open func on(clientEvent event: SocketClientEvent, callback: @escaping NormalCallback) -> UUID {
|
||||
return on(event.rawValue, callback: callback)
|
||||
}
|
||||
|
||||
/// Adds a single-use handler for a client event.
|
||||
///
|
||||
/// - parameter clientEvent: The event for this handler.
|
||||
/// - parameter callback: The callback that will execute when this event is received.
|
||||
/// - returns: A unique id for the handler that can be used to remove it.
|
||||
@discardableResult
|
||||
open func once(clientEvent event: SocketClientEvent, callback: @escaping NormalCallback) -> UUID {
|
||||
return once(event.rawValue, callback: callback)
|
||||
}
|
||||
|
||||
/// Adds a single-use handler for an event.
|
||||
///
|
||||
/// - parameter event: The event name for this handler.
|
||||
/// - parameter callback: The callback that will execute when this event is received.
|
||||
/// - returns: A unique id for the handler that can be used to remove it.
|
||||
@discardableResult
|
||||
open func once(_ event: String, callback: @escaping NormalCallback) -> UUID {
|
||||
DefaultSocketLogger.Logger.log("Adding once handler for event: \(event)", type: logType)
|
||||
|
||||
let id = UUID()
|
||||
|
||||
let handler = SocketEventHandler(event: event, id: id) {[weak self] data, ack in
|
||||
guard let this = self else { return }
|
||||
this.off(id: id)
|
||||
callback(data, ack)
|
||||
}
|
||||
|
||||
handlers.append(handler)
|
||||
|
||||
return handler.id
|
||||
}
|
||||
|
||||
/// Adds a handler that will be called on every event.
|
||||
///
|
||||
/// - parameter handler: The callback that will execute whenever an event is received.
|
||||
open func onAny(_ handler: @escaping (SocketAnyEvent) -> ()) {
|
||||
anyHandler = handler
|
||||
}
|
||||
|
||||
/// Tries to reconnect to the server.
|
||||
@available(*, unavailable, message: "Call the manager's reconnect method")
|
||||
open func reconnect() { }
|
||||
|
||||
/// Removes all handlers.
|
||||
///
|
||||
/// Can be used after disconnecting to break any potential remaining retain cycles.
|
||||
open func removeAllHandlers() {
|
||||
handlers.removeAll(keepingCapacity: false)
|
||||
}
|
||||
|
||||
/// Puts the socket back into the connecting state.
|
||||
/// Called when the manager detects a broken connection, or when a manual reconnect is triggered.
|
||||
///
|
||||
/// - parameter reason: The reason this socket is reconnecting.
|
||||
open func setReconnecting(reason: String) {
|
||||
status = .connecting
|
||||
|
||||
handleClientEvent(.reconnect, data: [reason])
|
||||
}
|
||||
|
||||
// Test properties
|
||||
|
||||
var testHandlers: [SocketEventHandler] {
|
||||
return handlers
|
||||
}
|
||||
|
||||
func setTestable() {
|
||||
status = .connected
|
||||
}
|
||||
|
||||
func setTestStatus(_ status: SocketIOStatus) {
|
||||
self.status = status
|
||||
}
|
||||
|
||||
func emitTest(event: String, _ data: Any...) {
|
||||
emit([event] + data)
|
||||
}
|
||||
}
|
||||
138
Source/SocketIO/Client/SocketIOClientConfiguration.swift
Normal file
138
Source/SocketIO/Client/SocketIOClientConfiguration.swift
Normal file
@ -0,0 +1,138 @@
|
||||
//
|
||||
// SocketIOClientConfiguration.swift
|
||||
// Socket.IO-Client-Swift
|
||||
//
|
||||
// Created by Erik Little on 8/13/16.
|
||||
//
|
||||
// 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.
|
||||
|
||||
/// An array-like type that holds `SocketIOClientOption`s
|
||||
public struct SocketIOClientConfiguration : ExpressibleByArrayLiteral, Collection, MutableCollection {
|
||||
// MARK: Typealiases
|
||||
|
||||
/// Type of element stored.
|
||||
public typealias Element = SocketIOClientOption
|
||||
|
||||
/// Index type.
|
||||
public typealias Index = Array<SocketIOClientOption>.Index
|
||||
|
||||
/// Iterator type.
|
||||
public typealias Iterator = Array<SocketIOClientOption>.Iterator
|
||||
|
||||
/// SubSequence type.
|
||||
public typealias SubSequence = Array<SocketIOClientOption>.SubSequence
|
||||
|
||||
// MARK: Properties
|
||||
|
||||
private var backingArray = [SocketIOClientOption]()
|
||||
|
||||
/// The start index of this collection.
|
||||
public var startIndex: Index {
|
||||
return backingArray.startIndex
|
||||
}
|
||||
|
||||
/// The end index of this collection.
|
||||
public var endIndex: Index {
|
||||
return backingArray.endIndex
|
||||
}
|
||||
|
||||
/// Whether this collection is empty.
|
||||
public var isEmpty: Bool {
|
||||
return backingArray.isEmpty
|
||||
}
|
||||
|
||||
/// The number of elements stored in this collection.
|
||||
public var count: Index.Stride {
|
||||
return backingArray.count
|
||||
}
|
||||
|
||||
/// The first element in this collection.
|
||||
public var first: Element? {
|
||||
return backingArray.first
|
||||
}
|
||||
|
||||
public subscript(position: Index) -> Element {
|
||||
get {
|
||||
return backingArray[position]
|
||||
}
|
||||
|
||||
set {
|
||||
backingArray[position] = newValue
|
||||
}
|
||||
}
|
||||
|
||||
public subscript(bounds: Range<Index>) -> SubSequence {
|
||||
get {
|
||||
return backingArray[bounds]
|
||||
}
|
||||
|
||||
set {
|
||||
backingArray[bounds] = newValue
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: Initializers
|
||||
|
||||
/// Creates a new `SocketIOClientConfiguration` from an array literal.
|
||||
///
|
||||
/// - parameter arrayLiteral: The elements.
|
||||
public init(arrayLiteral elements: Element...) {
|
||||
backingArray = elements
|
||||
}
|
||||
|
||||
// MARK: Methods
|
||||
|
||||
/// Creates an iterator for this collection.
|
||||
///
|
||||
/// - returns: An iterator over this collection.
|
||||
public func makeIterator() -> Iterator {
|
||||
return backingArray.makeIterator()
|
||||
}
|
||||
|
||||
/// - returns: The index after index.
|
||||
public func index(after i: Index) -> Index {
|
||||
return backingArray.index(after: i)
|
||||
}
|
||||
|
||||
/// Special method that inserts `element` into the collection, replacing any other instances of `element`.
|
||||
///
|
||||
/// - parameter element: The element to insert.
|
||||
/// - parameter replacing: Whether to replace any occurrences of element to the new item. Default is `true`.
|
||||
public mutating func insert(_ element: Element, replacing replace: Bool = true) {
|
||||
for i in 0..<backingArray.count where backingArray[i] == element {
|
||||
guard replace else { return }
|
||||
|
||||
backingArray[i] = element
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
backingArray.append(element)
|
||||
}
|
||||
}
|
||||
|
||||
/// Declares that a type can set configs from a `SocketIOClientConfiguration`.
|
||||
public protocol ConfigSettable {
|
||||
// MARK: Methods
|
||||
|
||||
/// Called when an `ConfigSettable` should set/update its configs from a given configuration.
|
||||
///
|
||||
/// - parameter config: The `SocketIOClientConfiguration` that should be used to set/update configs.
|
||||
mutating func setConfigs(_ config: SocketIOClientConfiguration)
|
||||
}
|
||||
241
Source/SocketIO/Client/SocketIOClientOption.swift
Normal file
241
Source/SocketIO/Client/SocketIOClientOption.swift
Normal file
@ -0,0 +1,241 @@
|
||||
//
|
||||
// SocketIOClientOption .swift
|
||||
// Socket.IO-Client-Swift
|
||||
//
|
||||
// Created by Erik Little on 10/17/15.
|
||||
//
|
||||
// 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.
|
||||
|
||||
import Foundation
|
||||
import Starscream
|
||||
|
||||
/// The socket.io version being used.
|
||||
public enum SocketIOVersion: Int {
|
||||
/// socket.io 2, engine.io 3
|
||||
case two = 2
|
||||
|
||||
/// socket.io 3, engine.io 4
|
||||
case three = 3
|
||||
}
|
||||
|
||||
protocol ClientOption : CustomStringConvertible, Equatable {
|
||||
func getSocketIOOptionValue() -> Any
|
||||
}
|
||||
|
||||
/// The options for a client.
|
||||
public enum SocketIOClientOption : ClientOption {
|
||||
/// If given, the WebSocket transport will attempt to use compression.
|
||||
case compress
|
||||
|
||||
/// A dictionary of GET parameters that will be included in the connect url.
|
||||
case connectParams([String: Any])
|
||||
|
||||
/// An array of cookies that will be sent during the initial connection.
|
||||
case cookies([HTTPCookie])
|
||||
|
||||
/// Any extra HTTP headers that should be sent during the initial connection.
|
||||
case extraHeaders([String: String])
|
||||
|
||||
/// If passed `true`, will cause the client to always create a new engine. Useful for debugging,
|
||||
/// or when you want to be sure no state from previous engines is being carried over.
|
||||
case forceNew(Bool)
|
||||
|
||||
/// If passed `true`, the only transport that will be used will be HTTP long-polling.
|
||||
case forcePolling(Bool)
|
||||
|
||||
/// If passed `true`, the only transport that will be used will be WebSockets.
|
||||
case forceWebsockets(Bool)
|
||||
|
||||
/// If passed `true`, the WebSocket stream will be configured with the enableSOCKSProxy `true`.
|
||||
case enableSOCKSProxy(Bool)
|
||||
|
||||
/// The queue that all interaction with the client should occur on. This is the queue that event handlers are
|
||||
/// called on.
|
||||
///
|
||||
/// **This should be a serial queue! Concurrent queues are not supported and might cause crashes and races**.
|
||||
case handleQueue(DispatchQueue)
|
||||
|
||||
/// If passed `true`, the client will log debug information. This should be turned off in production code.
|
||||
case log(Bool)
|
||||
|
||||
/// Used to pass in a custom logger.
|
||||
case logger(SocketLogger)
|
||||
|
||||
/// A custom path to socket.io. Only use this if the socket.io server is configured to look for this path.
|
||||
case path(String)
|
||||
|
||||
/// If passed `false`, the client will not reconnect when it loses connection. Useful if you want full control
|
||||
/// over when reconnects happen.
|
||||
case reconnects(Bool)
|
||||
|
||||
/// The number of times to try and reconnect before giving up. Pass `-1` to [never give up](https://www.youtube.com/watch?v=dQw4w9WgXcQ).
|
||||
case reconnectAttempts(Int)
|
||||
|
||||
/// The minimum number of seconds to wait before reconnect attempts.
|
||||
case reconnectWait(Int)
|
||||
|
||||
/// The maximum number of seconds to wait before reconnect attempts.
|
||||
case reconnectWaitMax(Int)
|
||||
|
||||
/// The randomization factor for calculating reconnect jitter.
|
||||
case randomizationFactor(Double)
|
||||
|
||||
/// Set `true` if your server is using secure transports.
|
||||
case secure(Bool)
|
||||
|
||||
/// Allows you to set which certs are valid. Useful for SSL pinning.
|
||||
case security(CertificatePinning)
|
||||
|
||||
/// If you're using a self-signed set. Only use for development.
|
||||
case selfSigned(Bool)
|
||||
|
||||
/// Sets an NSURLSessionDelegate for the underlying engine. Useful if you need to handle self-signed certs.
|
||||
case sessionDelegate(URLSessionDelegate)
|
||||
|
||||
/// If passed `false`, the WebSocket stream will be configured with the useCustomEngine `false`.
|
||||
case useCustomEngine(Bool)
|
||||
|
||||
/// The version of socket.io being used. This should match the server version. Default is 3.
|
||||
case version(SocketIOVersion)
|
||||
|
||||
// MARK: Properties
|
||||
|
||||
/// The description of this option.
|
||||
public var description: String {
|
||||
let description: String
|
||||
|
||||
switch self {
|
||||
case .compress:
|
||||
description = "compress"
|
||||
case .connectParams:
|
||||
description = "connectParams"
|
||||
case .cookies:
|
||||
description = "cookies"
|
||||
case .extraHeaders:
|
||||
description = "extraHeaders"
|
||||
case .forceNew:
|
||||
description = "forceNew"
|
||||
case .forcePolling:
|
||||
description = "forcePolling"
|
||||
case .forceWebsockets:
|
||||
description = "forceWebsockets"
|
||||
case .handleQueue:
|
||||
description = "handleQueue"
|
||||
case .log:
|
||||
description = "log"
|
||||
case .logger:
|
||||
description = "logger"
|
||||
case .path:
|
||||
description = "path"
|
||||
case .reconnects:
|
||||
description = "reconnects"
|
||||
case .reconnectAttempts:
|
||||
description = "reconnectAttempts"
|
||||
case .reconnectWait:
|
||||
description = "reconnectWait"
|
||||
case .reconnectWaitMax:
|
||||
description = "reconnectWaitMax"
|
||||
case .randomizationFactor:
|
||||
description = "randomizationFactor"
|
||||
case .secure:
|
||||
description = "secure"
|
||||
case .selfSigned:
|
||||
description = "selfSigned"
|
||||
case .security:
|
||||
description = "security"
|
||||
case .sessionDelegate:
|
||||
description = "sessionDelegate"
|
||||
case .enableSOCKSProxy:
|
||||
description = "enableSOCKSProxy"
|
||||
case .useCustomEngine:
|
||||
description = "customEngine"
|
||||
case .version:
|
||||
description = "version"
|
||||
}
|
||||
|
||||
return description
|
||||
}
|
||||
|
||||
func getSocketIOOptionValue() -> Any {
|
||||
let value: Any
|
||||
|
||||
switch self {
|
||||
case .compress:
|
||||
value = true
|
||||
case let .connectParams(params):
|
||||
value = params
|
||||
case let .cookies(cookies):
|
||||
value = cookies
|
||||
case let .extraHeaders(headers):
|
||||
value = headers
|
||||
case let .forceNew(force):
|
||||
value = force
|
||||
case let .forcePolling(force):
|
||||
value = force
|
||||
case let .forceWebsockets(force):
|
||||
value = force
|
||||
case let .handleQueue(queue):
|
||||
value = queue
|
||||
case let .log(log):
|
||||
value = log
|
||||
case let .logger(logger):
|
||||
value = logger
|
||||
case let .path(path):
|
||||
value = path
|
||||
case let .reconnects(reconnects):
|
||||
value = reconnects
|
||||
case let .reconnectAttempts(attempts):
|
||||
value = attempts
|
||||
case let .reconnectWait(wait):
|
||||
value = wait
|
||||
case let .reconnectWaitMax(wait):
|
||||
value = wait
|
||||
case let .randomizationFactor(factor):
|
||||
value = factor
|
||||
case let .secure(secure):
|
||||
value = secure
|
||||
case let .security(security):
|
||||
value = security
|
||||
case let .selfSigned(signed):
|
||||
value = signed
|
||||
case let .sessionDelegate(delegate):
|
||||
value = delegate
|
||||
case let .enableSOCKSProxy(enable):
|
||||
value = enable
|
||||
case let .useCustomEngine(enable):
|
||||
value = enable
|
||||
case let.version(versionNum):
|
||||
value = versionNum
|
||||
}
|
||||
|
||||
return value
|
||||
}
|
||||
|
||||
// MARK: Operators
|
||||
|
||||
/// Compares whether two options are the same.
|
||||
///
|
||||
/// - parameter lhs: Left operand to compare.
|
||||
/// - parameter rhs: Right operand to compare.
|
||||
/// - returns: `true` if the two are the same option.
|
||||
public static func ==(lhs: SocketIOClientOption, rhs: SocketIOClientOption) -> Bool {
|
||||
return lhs.description == rhs.description
|
||||
}
|
||||
|
||||
}
|
||||
392
Source/SocketIO/Client/SocketIOClientSpec.swift
Normal file
392
Source/SocketIO/Client/SocketIOClientSpec.swift
Normal file
@ -0,0 +1,392 @@
|
||||
//
|
||||
// SocketIOClientSpec.swift
|
||||
// Socket.IO-Client-Swift
|
||||
//
|
||||
// Created by Erik Little on 1/3/16.
|
||||
//
|
||||
// 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.
|
||||
|
||||
import Dispatch
|
||||
import Foundation
|
||||
|
||||
/// Defines the interface for a SocketIOClient.
|
||||
public protocol SocketIOClientSpec : AnyObject {
|
||||
// MARK: Properties
|
||||
|
||||
/// A handler that will be called on any event.
|
||||
var anyHandler: ((SocketAnyEvent) -> ())? { get }
|
||||
|
||||
/// The array of handlers for this socket.
|
||||
var handlers: [SocketEventHandler] { get }
|
||||
|
||||
/// The manager for this socket.
|
||||
var manager: SocketManagerSpec? { get }
|
||||
|
||||
/// The namespace that this socket is currently connected to.
|
||||
///
|
||||
/// **Must** start with a `/`.
|
||||
var nsp: String { get }
|
||||
|
||||
/// A view into this socket where emits do not check for binary data.
|
||||
///
|
||||
/// Usage:
|
||||
///
|
||||
/// ```swift
|
||||
/// socket.rawEmitView.emit("myEvent", myObject)
|
||||
/// ```
|
||||
///
|
||||
/// **NOTE**: It is not safe to hold on to this view beyond the life of the socket.
|
||||
var rawEmitView: SocketRawView { get }
|
||||
|
||||
/// The id of this socket.io connect. This is different from the sid of the engine.io connection.
|
||||
var sid: String? { get }
|
||||
|
||||
/// The status of this client.
|
||||
var status: SocketIOStatus { get }
|
||||
|
||||
// MARK: Methods
|
||||
|
||||
/// Connect to the server. The same as calling `connect(timeoutAfter:withHandler:)` with a timeout of 0.
|
||||
///
|
||||
/// Only call after adding your event listeners, unless you know what you're doing.
|
||||
///
|
||||
/// - parameter payload: An optional payload sent on connect
|
||||
func connect(withPayload payload: [String: Any]?)
|
||||
|
||||
/// Connect to the server. If we aren't connected after `timeoutAfter` seconds, then `withHandler` is called.
|
||||
///
|
||||
/// Only call after adding your event listeners, unless you know what you're doing.
|
||||
///
|
||||
/// - parameter withPayload: An optional payload sent on connect
|
||||
/// - parameter timeoutAfter: The number of seconds after which if we are not connected we assume the connection
|
||||
/// has failed. Pass 0 to never timeout.
|
||||
/// - parameter handler: The handler to call when the client fails to connect.
|
||||
func connect(withPayload payload: [String: Any]?, timeoutAfter: Double, withHandler handler: (() -> ())?)
|
||||
|
||||
/// Called when the client connects to a namespace. If the client was created with a namespace upfront,
|
||||
/// then this is only called when the client connects to that namespace.
|
||||
///
|
||||
/// - parameter toNamespace: The namespace that was connected to.
|
||||
func didConnect(toNamespace namespace: String, payload: [String: Any]?)
|
||||
|
||||
/// Called when the client has disconnected from socket.io.
|
||||
///
|
||||
/// - parameter reason: The reason for the disconnection.
|
||||
func didDisconnect(reason: String)
|
||||
|
||||
/// Called when the client encounters an error.
|
||||
///
|
||||
/// - parameter reason: The reason for the disconnection.
|
||||
func didError(reason: String)
|
||||
|
||||
/// Disconnects the socket.
|
||||
func disconnect()
|
||||
|
||||
/// Send an event to the server, with optional data items and optional write completion handler.
|
||||
///
|
||||
/// If an error occurs trying to transform `items` into their socket representation, a `SocketClientEvent.error`
|
||||
/// will be emitted. The structure of the error data is `[eventName, items, theError]`
|
||||
///
|
||||
/// - parameter event: The event to send.
|
||||
/// - parameter items: The items to send with this event. May be left out.
|
||||
/// - parameter completion: Callback called on transport write completion.
|
||||
func emit(_ event: String, _ items: SocketData..., completion: (() -> ())?)
|
||||
|
||||
/// Send an event to the server, with optional data items and optional write completion handler.
|
||||
///
|
||||
/// If an error occurs trying to transform `items` into their socket representation, a `SocketClientEvent.error`
|
||||
/// will be emitted. The structure of the error data is `[eventName, items, theError]`
|
||||
///
|
||||
/// - parameter event: The event to send.
|
||||
/// - parameter items: The items to send with this event. May be left out.
|
||||
/// - parameter completion: Callback called on transport write completion.
|
||||
func emit(_ event: String, with items: [SocketData], completion: (() -> ())?)
|
||||
|
||||
/// Call when you wish to tell the server that you've received the event for `ack`.
|
||||
///
|
||||
/// - parameter ack: The ack number.
|
||||
/// - parameter with: The data for this ack.
|
||||
func emitAck(_ ack: Int, with items: [Any])
|
||||
|
||||
/// Sends a message to the server, requesting an ack.
|
||||
///
|
||||
/// **NOTE**: It is up to the server send an ack back, just calling this method does not mean the server will ack.
|
||||
/// Check that your server's api will ack the event being sent.
|
||||
///
|
||||
/// If an error occurs trying to transform `items` into their socket representation, a `SocketClientEvent.error`
|
||||
/// will be emitted. The structure of the error data is `[eventName, items, theError]`
|
||||
///
|
||||
/// Example:
|
||||
///
|
||||
/// ```swift
|
||||
/// socket.emitWithAck("myEvent", 1).timingOut(after: 1) {data in
|
||||
/// ...
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// - parameter event: The event to send.
|
||||
/// - parameter items: The items to send with this event. May be left out.
|
||||
/// - returns: An `OnAckCallback`. You must call the `timingOut(after:)` method before the event will be sent.
|
||||
func emitWithAck(_ event: String, _ items: SocketData...) -> OnAckCallback
|
||||
|
||||
/// Sends a message to the server, requesting an ack.
|
||||
///
|
||||
/// **NOTE**: It is up to the server send an ack back, just calling this method does not mean the server will ack.
|
||||
/// Check that your server's api will ack the event being sent.
|
||||
///
|
||||
/// If an error occurs trying to transform `items` into their socket representation, a `SocketClientEvent.error`
|
||||
/// will be emitted. The structure of the error data is `[eventName, items, theError]`
|
||||
///
|
||||
/// Example:
|
||||
///
|
||||
/// ```swift
|
||||
/// socket.emitWithAck("myEvent", 1).timingOut(after: 1) {data in
|
||||
/// ...
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// - parameter event: The event to send.
|
||||
/// - parameter items: The items to send with this event. May be left out.
|
||||
/// - returns: An `OnAckCallback`. You must call the `timingOut(after:)` method before the event will be sent.
|
||||
func emitWithAck(_ event: String, with items: [SocketData]) -> OnAckCallback
|
||||
|
||||
/// Called when socket.io has acked one of our emits. Causes the corresponding ack callback to be called.
|
||||
///
|
||||
/// - parameter ack: The number for this ack.
|
||||
/// - parameter data: The data sent back with this ack.
|
||||
func handleAck(_ ack: Int, data: [Any])
|
||||
|
||||
/// Called on socket.io specific events.
|
||||
///
|
||||
/// - parameter event: The `SocketClientEvent`.
|
||||
/// - parameter data: The data for this event.
|
||||
func handleClientEvent(_ event: SocketClientEvent, data: [Any])
|
||||
|
||||
/// Called when we get an event from socket.io.
|
||||
///
|
||||
/// - parameter event: The name of the event.
|
||||
/// - parameter data: The data that was sent with this event.
|
||||
/// - parameter isInternalMessage: Whether this event was sent internally. If `true` it is always sent to handlers.
|
||||
/// - parameter ack: If > 0 then this event expects to get an ack back from the client.
|
||||
func handleEvent(_ event: String, data: [Any], isInternalMessage: Bool, withAck ack: Int)
|
||||
|
||||
/// Causes a client to handle a socket.io packet. The namespace for the packet must match the namespace of the
|
||||
/// socket.
|
||||
///
|
||||
/// - parameter packet: The packet to handle.
|
||||
func handlePacket(_ packet: SocketPacket)
|
||||
|
||||
/// Call when you wish to leave a namespace and disconnect this socket.
|
||||
func leaveNamespace()
|
||||
|
||||
/// Joins `nsp`. You shouldn't need to call this directly, instead call `connect`.
|
||||
///
|
||||
/// - Parameter withPayload: The payload to connect when joining this namespace
|
||||
func joinNamespace(withPayload payload: [String: Any]?)
|
||||
|
||||
/// Removes handler(s) for a client event.
|
||||
///
|
||||
/// If you wish to remove a client event handler, call the `off(id:)` with the UUID received from its `on` call.
|
||||
///
|
||||
/// - parameter clientEvent: The event to remove handlers for.
|
||||
func off(clientEvent event: SocketClientEvent)
|
||||
|
||||
/// Removes handler(s) based on an event name.
|
||||
///
|
||||
/// If you wish to remove a specific event, call the `off(id:)` with the UUID received from its `on` call.
|
||||
///
|
||||
/// - parameter event: The event to remove handlers for.
|
||||
func off(_ event: String)
|
||||
|
||||
/// Removes a handler with the specified UUID gotten from an `on` or `once`
|
||||
///
|
||||
/// If you want to remove all events for an event, call the off `off(_:)` method with the event name.
|
||||
///
|
||||
/// - parameter id: The UUID of the handler you wish to remove.
|
||||
func off(id: UUID)
|
||||
|
||||
/// Adds a handler for an event.
|
||||
///
|
||||
/// - parameter event: The event name for this handler.
|
||||
/// - parameter callback: The callback that will execute when this event is received.
|
||||
/// - returns: A unique id for the handler that can be used to remove it.
|
||||
func on(_ event: String, callback: @escaping NormalCallback) -> UUID
|
||||
|
||||
/// Adds a handler for a client event.
|
||||
///
|
||||
/// Example:
|
||||
///
|
||||
/// ```swift
|
||||
/// socket.on(clientEvent: .connect) {data, ack in
|
||||
/// ...
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// - parameter event: The event for this handler.
|
||||
/// - parameter callback: The callback that will execute when this event is received.
|
||||
/// - returns: A unique id for the handler that can be used to remove it.
|
||||
func on(clientEvent event: SocketClientEvent, callback: @escaping NormalCallback) -> UUID
|
||||
|
||||
/// Adds a single-use handler for a client event.
|
||||
///
|
||||
/// - parameter clientEvent: The event for this handler.
|
||||
/// - parameter callback: The callback that will execute when this event is received.
|
||||
/// - returns: A unique id for the handler that can be used to remove it.
|
||||
func once(clientEvent event: SocketClientEvent, callback: @escaping NormalCallback) -> UUID
|
||||
|
||||
/// Adds a single-use handler for an event.
|
||||
///
|
||||
/// - parameter event: The event name for this handler.
|
||||
/// - parameter callback: The callback that will execute when this event is received.
|
||||
/// - returns: A unique id for the handler that can be used to remove it.
|
||||
func once(_ event: String, callback: @escaping NormalCallback) -> UUID
|
||||
|
||||
/// Adds a handler that will be called on every event.
|
||||
///
|
||||
/// - parameter handler: The callback that will execute whenever an event is received.
|
||||
func onAny(_ handler: @escaping (SocketAnyEvent) -> ())
|
||||
|
||||
/// Removes all handlers.
|
||||
///
|
||||
/// Can be used after disconnecting to break any potential remaining retain cycles.
|
||||
func removeAllHandlers()
|
||||
|
||||
/// Puts the socket back into the connecting state.
|
||||
/// Called when the manager detects a broken connection, or when a manual reconnect is triggered.
|
||||
///
|
||||
/// parameter reason: The reason this socket is going reconnecting.
|
||||
func setReconnecting(reason: String)
|
||||
}
|
||||
|
||||
public extension SocketIOClientSpec {
|
||||
/// Default implementation.
|
||||
func didError(reason: String) {
|
||||
DefaultSocketLogger.Logger.error("\(reason)", type: "SocketIOClient")
|
||||
|
||||
handleClientEvent(.error, data: [reason])
|
||||
}
|
||||
}
|
||||
|
||||
/// The set of events that are generated by the client.
|
||||
public enum SocketClientEvent : String {
|
||||
// MARK: Cases
|
||||
|
||||
/// Emitted when the client connects. This is also called on a successful reconnection. A connect event gets one
|
||||
/// data item: the namespace that was connected to.
|
||||
///
|
||||
/// ```swift
|
||||
/// socket.on(clientEvent: .connect) {data, ack in
|
||||
/// guard let nsp = data[0] as? String else { return }
|
||||
/// // Some logic using the nsp
|
||||
/// }
|
||||
/// ```
|
||||
case connect
|
||||
|
||||
/// Emitted when the socket has disconnected and will not attempt to try to reconnect.
|
||||
///
|
||||
/// Usage:
|
||||
///
|
||||
/// ```swift
|
||||
/// socket.on(clientEvent: .disconnect) {data, ack in
|
||||
/// // Some cleanup logic
|
||||
/// }
|
||||
/// ```
|
||||
case disconnect
|
||||
|
||||
/// Emitted when an error occurs.
|
||||
///
|
||||
/// Usage:
|
||||
///
|
||||
/// ```swift
|
||||
/// socket.on(clientEvent: .error) {data, ack in
|
||||
/// // Some logging
|
||||
/// }
|
||||
/// ```
|
||||
case error
|
||||
|
||||
/// Emitted whenever the engine sends a ping.
|
||||
///
|
||||
/// Usage:
|
||||
///
|
||||
/// ```swift
|
||||
/// socket.on(clientEvent: .ping) {_, _ in
|
||||
/// // Maybe keep track of latency?
|
||||
/// }
|
||||
/// ```
|
||||
case ping
|
||||
|
||||
/// Emitted whenever the engine gets a pong.
|
||||
///
|
||||
/// Usage:
|
||||
///
|
||||
/// ```swift
|
||||
/// socket.on(clientEvent: .pong) {_, _ in
|
||||
/// // Maybe keep track of latency?
|
||||
/// }
|
||||
/// ```
|
||||
case pong
|
||||
|
||||
/// Emitted when the client begins the reconnection process.
|
||||
///
|
||||
/// Usage:
|
||||
///
|
||||
/// ```swift
|
||||
/// socket.on(clientEvent: .reconnect) {data, ack in
|
||||
/// // Some reconnect event logic
|
||||
/// }
|
||||
/// ```
|
||||
case reconnect
|
||||
|
||||
/// Emitted each time the client tries to reconnect to the server.
|
||||
///
|
||||
/// Usage:
|
||||
///
|
||||
/// ```swift
|
||||
/// socket.on(clientEvent: .reconnectAttempt) {data, ack in
|
||||
/// // Some reconnect attempt logging
|
||||
/// }
|
||||
/// ```
|
||||
case reconnectAttempt
|
||||
|
||||
/// Emitted every time there is a change in the client's status.
|
||||
///
|
||||
/// The payload for data is [SocketIOClientStatus, Int]. Where the second item is the raw value. Use the second one
|
||||
/// if you are working in Objective-C.
|
||||
///
|
||||
/// Usage:
|
||||
///
|
||||
/// ```swift
|
||||
/// socket.on(clientEvent: .statusChange) {data, ack in
|
||||
/// // Some status changing logging
|
||||
/// }
|
||||
/// ```
|
||||
case statusChange
|
||||
|
||||
/// Emitted when when upgrading the http connection to a websocket connection.
|
||||
///
|
||||
/// Usage:
|
||||
///
|
||||
/// ```swift
|
||||
/// socket.on(clientEvent: .websocketUpgrade) {data, ack in
|
||||
/// let headers = (data as [Any])[0]
|
||||
/// // Some header logic
|
||||
/// }
|
||||
/// ```
|
||||
case websocketUpgrade
|
||||
}
|
||||
@ -1,5 +1,5 @@
|
||||
//
|
||||
// SocketIOClientStatus.swift
|
||||
// SocketIOStatus.swift
|
||||
// Socket.IO-Client-Swift
|
||||
//
|
||||
// Created by Erik Little on 8/14/15.
|
||||
@ -24,9 +24,36 @@
|
||||
|
||||
import Foundation
|
||||
|
||||
/// **NotConnected**: initial state
|
||||
///
|
||||
/// **Disconnected**: connected before
|
||||
@objc public enum SocketIOClientStatus : Int {
|
||||
case NotConnected, Disconnected, Connecting, Connected
|
||||
/// Represents state of a manager or client.
|
||||
@objc
|
||||
public enum SocketIOStatus : Int, CustomStringConvertible {
|
||||
// MARK: Cases
|
||||
|
||||
/// The client/manager has never been connected. Or the client has been reset.
|
||||
case notConnected
|
||||
|
||||
/// The client/manager was once connected, but not anymore.
|
||||
case disconnected
|
||||
|
||||
/// The client/manager is in the process of connecting.
|
||||
case connecting
|
||||
|
||||
/// The client/manager is currently connected.
|
||||
case connected
|
||||
|
||||
// MARK: Properties
|
||||
|
||||
/// - returns: True if this client/manager is connected/connecting to a server.
|
||||
public var active: Bool {
|
||||
return self == .connected || self == .connecting
|
||||
}
|
||||
|
||||
public var description: String {
|
||||
switch self {
|
||||
case .connected: return "connected"
|
||||
case .connecting: return "connecting"
|
||||
case .disconnected: return "disconnected"
|
||||
case .notConnected: return "notConnected"
|
||||
}
|
||||
}
|
||||
}
|
||||
163
Source/SocketIO/Client/SocketRawView.swift
Normal file
163
Source/SocketIO/Client/SocketRawView.swift
Normal file
@ -0,0 +1,163 @@
|
||||
//
|
||||
// SocketRawView.swift
|
||||
// Socket.IO-Client-Swift
|
||||
//
|
||||
// Created by Erik Little on 3/30/18.
|
||||
//
|
||||
// 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.
|
||||
|
||||
import Foundation
|
||||
|
||||
/// Class that gives a backwards compatible way to cause an emit not to recursively check for Data objects.
|
||||
///
|
||||
/// Usage:
|
||||
///
|
||||
/// ```swift
|
||||
/// socket.rawEmitView.emit("myEvent", myObject)
|
||||
/// ```
|
||||
public final class SocketRawView : NSObject {
|
||||
private unowned let socket: SocketIOClient
|
||||
|
||||
init(socket: SocketIOClient) {
|
||||
self.socket = socket
|
||||
}
|
||||
|
||||
/// Send an event to the server, with optional data items.
|
||||
///
|
||||
/// If an error occurs trying to transform `items` into their socket representation, a `SocketClientEvent.error`
|
||||
/// will be emitted. The structure of the error data is `[eventName, items, theError]`
|
||||
///
|
||||
/// - parameter event: The event to send.
|
||||
/// - parameter items: The items to send with this event. May be left out.
|
||||
public func emit(_ event: String, _ items: SocketData...) {
|
||||
do {
|
||||
try emit(event, with: items.map({ try $0.socketRepresentation() }))
|
||||
} catch {
|
||||
DefaultSocketLogger.Logger.error("Error creating socketRepresentation for emit: \(event), \(items)",
|
||||
type: "SocketIOClient")
|
||||
|
||||
socket.handleClientEvent(.error, data: [event, items, error])
|
||||
}
|
||||
}
|
||||
|
||||
/// Same as emit, but meant for Objective-C
|
||||
///
|
||||
/// - parameter event: The event to send.
|
||||
/// - parameter items: The items to send with this event. Send an empty array to send no data.
|
||||
@objc
|
||||
public func emit(_ event: String, with items: [Any]) {
|
||||
socket.emit([event] + items, binary: false)
|
||||
}
|
||||
|
||||
/// Sends a message to the server, requesting an ack.
|
||||
///
|
||||
/// **NOTE**: It is up to the server send an ack back, just calling this method does not mean the server will ack.
|
||||
/// Check that your server's api will ack the event being sent.
|
||||
///
|
||||
/// If an error occurs trying to transform `items` into their socket representation, a `SocketClientEvent.error`
|
||||
/// will be emitted. The structure of the error data is `[eventName, items, theError]`
|
||||
///
|
||||
/// Example:
|
||||
///
|
||||
/// ```swift
|
||||
/// socket.emitWithAck("myEvent", 1).timingOut(after: 1) {data in
|
||||
/// ...
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// - parameter event: The event to send.
|
||||
/// - parameter items: The items to send with this event. May be left out.
|
||||
/// - returns: An `OnAckCallback`. You must call the `timingOut(after:)` method before the event will be sent.
|
||||
public func emitWithAck(_ event: String, _ items: SocketData...) -> OnAckCallback {
|
||||
do {
|
||||
return emitWithAck(event, with: try items.map({ try $0.socketRepresentation() }))
|
||||
} catch {
|
||||
DefaultSocketLogger.Logger.error("Error creating socketRepresentation for emit: \(event), \(items)",
|
||||
type: "SocketIOClient")
|
||||
|
||||
socket.handleClientEvent(.error, data: [event, items, error])
|
||||
|
||||
return OnAckCallback(ackNumber: -1, items: [], socket: socket)
|
||||
}
|
||||
}
|
||||
|
||||
/// Same as emitWithAck, but for Objective-C
|
||||
///
|
||||
/// **NOTE**: It is up to the server send an ack back, just calling this method does not mean the server will ack.
|
||||
/// Check that your server's api will ack the event being sent.
|
||||
///
|
||||
/// Example:
|
||||
///
|
||||
/// ```swift
|
||||
/// socket.emitWithAck("myEvent", with: [1]).timingOut(after: 1) {data in
|
||||
/// ...
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// - parameter event: The event to send.
|
||||
/// - parameter items: The items to send with this event. Use `[]` to send nothing.
|
||||
/// - returns: An `OnAckCallback`. You must call the `timingOut(after:)` method before the event will be sent.
|
||||
@objc
|
||||
public func emitWithAck(_ event: String, with items: [Any]) -> OnAckCallback {
|
||||
return socket.createOnAck([event] + items, binary: false)
|
||||
}
|
||||
}
|
||||
|
||||
/// Class that gives a backwards compatible way to cause an emit not to recursively check for Data objects.
|
||||
///
|
||||
/// Usage:
|
||||
///
|
||||
/// ```swift
|
||||
/// ack.rawEmitView.with(myObject)
|
||||
/// ```
|
||||
public final class SocketRawAckView : NSObject {
|
||||
private unowned let socket: SocketIOClient
|
||||
private let ackNum: Int
|
||||
|
||||
init(socket: SocketIOClient, ackNum: Int) {
|
||||
self.socket = socket
|
||||
self.ackNum = ackNum
|
||||
}
|
||||
|
||||
/// Call to ack receiving this event.
|
||||
///
|
||||
/// If an error occurs trying to transform `items` into their socket representation, a `SocketClientEvent.error`
|
||||
/// will be emitted. The structure of the error data is `[ackNum, items, theError]`
|
||||
///
|
||||
/// - parameter items: A variable number of items to send when acking.
|
||||
public func with(_ items: SocketData...) {
|
||||
guard ackNum != -1 else { return }
|
||||
|
||||
do {
|
||||
socket.emit(try items.map({ try $0.socketRepresentation() }), ack: ackNum, binary: false, isAck: true)
|
||||
} catch {
|
||||
socket.handleClientEvent(.error, data: [ackNum, items, error])
|
||||
}
|
||||
}
|
||||
|
||||
/// Call to ack receiving this event.
|
||||
///
|
||||
/// - parameter items: An array of items to send when acking. Use `[]` to send nothing.
|
||||
@objc
|
||||
public func with(_ items: [Any]) {
|
||||
guard ackNum != -1 else { return }
|
||||
|
||||
socket.emit(items, ack: ackNum, binary: false, isAck: true)
|
||||
}
|
||||
}
|
||||
778
Source/SocketIO/Engine/SocketEngine.swift
Normal file
778
Source/SocketIO/Engine/SocketEngine.swift
Normal file
@ -0,0 +1,778 @@
|
||||
//
|
||||
// SocketEngine.swift
|
||||
// Socket.IO-Client-Swift
|
||||
//
|
||||
// Created by Erik Little on 3/3/15.
|
||||
//
|
||||
// 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.
|
||||
|
||||
import Dispatch
|
||||
import Foundation
|
||||
import Starscream
|
||||
|
||||
/// The class that handles the engine.io protocol and transports.
|
||||
/// See `SocketEnginePollable` and `SocketEngineWebsocket` for transport specific methods.
|
||||
open class SocketEngine: NSObject, WebSocketDelegate, URLSessionDelegate,
|
||||
SocketEnginePollable, SocketEngineWebsocket, ConfigSettable {
|
||||
|
||||
|
||||
// MARK: Properties
|
||||
|
||||
private static let logType = "SocketEngine"
|
||||
|
||||
/// The queue that all engine actions take place on.
|
||||
public let engineQueue = DispatchQueue(label: "com.socketio.engineHandleQueue")
|
||||
|
||||
/// The connect parameters sent during a connect.
|
||||
public var connectParams: [String: Any]? {
|
||||
didSet {
|
||||
(urlPolling, urlWebSocket) = createURLs()
|
||||
}
|
||||
}
|
||||
|
||||
/// A dictionary of extra http headers that will be set during connection.
|
||||
public var extraHeaders: [String: String]?
|
||||
|
||||
/// A queue of engine.io messages waiting for POSTing
|
||||
///
|
||||
/// **You should not touch this directly**
|
||||
public var postWait = [Post]()
|
||||
|
||||
/// `true` if there is an outstanding poll. Trying to poll before the first is done will cause socket.io to
|
||||
/// disconnect us.
|
||||
///
|
||||
/// **Do not touch this directly**
|
||||
public var waitingForPoll = false
|
||||
|
||||
/// `true` if there is an outstanding post. Trying to post before the first is done will cause socket.io to
|
||||
/// disconnect us.
|
||||
///
|
||||
/// **Do not touch this directly**
|
||||
public var waitingForPost = false
|
||||
|
||||
/// `true` if this engine is closed.
|
||||
public private(set) var closed = false
|
||||
|
||||
/// If `true` the engine will attempt to use WebSocket compression.
|
||||
public private(set) var compress = false
|
||||
|
||||
/// `true` if this engine is connected. Connected means that the initial poll connect has succeeded.
|
||||
public private(set) var connected = false
|
||||
|
||||
/// An array of HTTPCookies that are sent during the connection.
|
||||
public private(set) var cookies: [HTTPCookie]?
|
||||
|
||||
/// When `true`, the engine is in the process of switching to WebSockets.
|
||||
///
|
||||
/// **Do not touch this directly**
|
||||
public private(set) var fastUpgrade = false
|
||||
|
||||
/// When `true`, the engine will only use HTTP long-polling as a transport.
|
||||
public private(set) var forcePolling = false
|
||||
|
||||
/// When `true`, the engine will only use WebSockets as a transport.
|
||||
public private(set) var forceWebsockets = false
|
||||
|
||||
/// `true` If engine's session has been invalidated.
|
||||
public private(set) var invalidated = false
|
||||
|
||||
/// If `true`, the engine is currently in HTTP long-polling mode.
|
||||
public private(set) var polling = true
|
||||
|
||||
/// If `true`, the engine is currently seeing whether it can upgrade to WebSockets.
|
||||
public private(set) var probing = false
|
||||
|
||||
/// The URLSession that will be used for polling.
|
||||
public private(set) var session: URLSession?
|
||||
|
||||
/// The session id for this engine.
|
||||
public private(set) var sid = ""
|
||||
|
||||
/// The path to engine.io.
|
||||
public private(set) var socketPath = "/engine.io/"
|
||||
|
||||
/// The url for polling.
|
||||
public private(set) var urlPolling = URL(string: "http://localhost/")!
|
||||
|
||||
/// The url for WebSockets.
|
||||
public private(set) var urlWebSocket = URL(string: "http://localhost/")!
|
||||
|
||||
/// When `false`, the WebSocket `stream` will be configured with the useCustomEngine `false`.
|
||||
public private(set) var useCustomEngine = true
|
||||
|
||||
/// The version of engine.io being used. Default is three.
|
||||
public private(set) var version: SocketIOVersion = .three
|
||||
|
||||
/// If `true`, then the engine is currently in WebSockets mode.
|
||||
@available(*, deprecated, message: "No longer needed, if we're not polling, then we must be doing websockets")
|
||||
public private(set) var websocket = false
|
||||
|
||||
/// When `true`, the WebSocket `stream` will be configured with the enableSOCKSProxy `true`.
|
||||
public private(set) var enableSOCKSProxy = false
|
||||
|
||||
/// The WebSocket for this engine.
|
||||
public private(set) var ws: WebSocket?
|
||||
|
||||
/// Whether or not the WebSocket is currently connected.
|
||||
public private(set) var wsConnected = false
|
||||
|
||||
/// The client for this engine.
|
||||
public weak var client: SocketEngineClient?
|
||||
|
||||
private weak var sessionDelegate: URLSessionDelegate?
|
||||
|
||||
private let url: URL
|
||||
|
||||
private var lastCommunication: Date?
|
||||
private var pingInterval: Int?
|
||||
private var pingTimeout = 0 {
|
||||
didSet {
|
||||
pongsMissedMax = Int(pingTimeout / (pingInterval ?? 25000))
|
||||
}
|
||||
}
|
||||
|
||||
private var pongsMissed = 0
|
||||
private var pongsMissedMax = 0
|
||||
private var probeWait = ProbeWaitQueue()
|
||||
private var secure = false
|
||||
private var certPinner: CertificatePinning?
|
||||
private var selfSigned = false
|
||||
|
||||
// MARK: Initializers
|
||||
|
||||
/// Creates a new engine.
|
||||
///
|
||||
/// - parameter client: The client for this engine.
|
||||
/// - parameter url: The url for this engine.
|
||||
/// - parameter config: An array of configuration options for this engine.
|
||||
public init(client: SocketEngineClient, url: URL, config: SocketIOClientConfiguration) {
|
||||
self.client = client
|
||||
self.url = url
|
||||
|
||||
super.init()
|
||||
|
||||
setConfigs(config)
|
||||
|
||||
sessionDelegate = sessionDelegate ?? self
|
||||
|
||||
(urlPolling, urlWebSocket) = createURLs()
|
||||
}
|
||||
|
||||
/// Creates a new engine.
|
||||
///
|
||||
/// - parameter client: The client for this engine.
|
||||
/// - parameter url: The url for this engine.
|
||||
/// - parameter options: The options for this engine.
|
||||
public required convenience init(client: SocketEngineClient, url: URL, options: [String: Any]?) {
|
||||
self.init(client: client, url: url, config: options?.toSocketConfiguration() ?? [])
|
||||
}
|
||||
|
||||
/// :nodoc:
|
||||
deinit {
|
||||
DefaultSocketLogger.Logger.log("Engine is being released", type: SocketEngine.logType)
|
||||
closed = true
|
||||
stopPolling()
|
||||
}
|
||||
|
||||
// MARK: Methods
|
||||
|
||||
private func checkAndHandleEngineError(_ msg: String) {
|
||||
do {
|
||||
let dict = try msg.toDictionary()
|
||||
guard let error = dict["message"] as? String else { return }
|
||||
|
||||
/*
|
||||
0: Unknown transport
|
||||
1: Unknown sid
|
||||
2: Bad handshake request
|
||||
3: Bad request
|
||||
*/
|
||||
didError(reason: error)
|
||||
} catch {
|
||||
client?.engineDidError(reason: "Got unknown error from server \(msg)")
|
||||
}
|
||||
}
|
||||
|
||||
private func handleBase64(message: String) {
|
||||
let offset = version.rawValue >= 3 ? 1 : 2
|
||||
// binary in base64 string
|
||||
let noPrefix = String(message[message.index(message.startIndex, offsetBy: offset)..<message.endIndex])
|
||||
|
||||
if let data = Data(base64Encoded: noPrefix, options: .ignoreUnknownCharacters) {
|
||||
client?.parseEngineBinaryData(data)
|
||||
}
|
||||
}
|
||||
|
||||
private func closeOutEngine(reason: String) {
|
||||
sid = ""
|
||||
closed = true
|
||||
invalidated = true
|
||||
connected = false
|
||||
|
||||
ws?.disconnect()
|
||||
stopPolling()
|
||||
client?.engineDidClose(reason: reason)
|
||||
}
|
||||
|
||||
/// Starts the connection to the server.
|
||||
open func connect() {
|
||||
engineQueue.async {
|
||||
self._connect()
|
||||
}
|
||||
}
|
||||
|
||||
private func _connect() {
|
||||
if connected {
|
||||
DefaultSocketLogger.Logger.error("Engine tried opening while connected. Assuming this was a reconnect",
|
||||
type: SocketEngine.logType)
|
||||
_disconnect(reason: "reconnect")
|
||||
}
|
||||
|
||||
DefaultSocketLogger.Logger.log("Starting engine. Server: \(url)", type: SocketEngine.logType)
|
||||
DefaultSocketLogger.Logger.log("Handshaking", type: SocketEngine.logType)
|
||||
|
||||
resetEngine()
|
||||
|
||||
if forceWebsockets {
|
||||
polling = false
|
||||
createWebSocketAndConnect()
|
||||
return
|
||||
}
|
||||
|
||||
var reqPolling = URLRequest(url: urlPolling, cachePolicy: .reloadIgnoringLocalCacheData, timeoutInterval: 60.0)
|
||||
|
||||
addHeaders(to: &reqPolling)
|
||||
doLongPoll(for: reqPolling)
|
||||
}
|
||||
|
||||
private func createURLs() -> (URL, URL) {
|
||||
if client == nil {
|
||||
return (URL(string: "http://localhost/")!, URL(string: "http://localhost/")!)
|
||||
}
|
||||
|
||||
var urlPolling = URLComponents(string: url.absoluteString)!
|
||||
var urlWebSocket = URLComponents(string: url.absoluteString)!
|
||||
var queryString = ""
|
||||
|
||||
urlWebSocket.path = socketPath
|
||||
urlPolling.path = socketPath
|
||||
|
||||
if secure {
|
||||
urlPolling.scheme = "https"
|
||||
urlWebSocket.scheme = "wss"
|
||||
} else {
|
||||
urlPolling.scheme = "http"
|
||||
urlWebSocket.scheme = "ws"
|
||||
}
|
||||
|
||||
if let connectParams = self.connectParams {
|
||||
for (key, value) in connectParams {
|
||||
let keyEsc = key.urlEncode()!
|
||||
let valueEsc = "\(value)".urlEncode()!
|
||||
|
||||
queryString += "&\(keyEsc)=\(valueEsc)"
|
||||
}
|
||||
}
|
||||
|
||||
urlWebSocket.percentEncodedQuery = "transport=websocket" + queryString
|
||||
urlPolling.percentEncodedQuery = "transport=polling&b64=1" + queryString
|
||||
|
||||
if !urlWebSocket.percentEncodedQuery!.contains("EIO") {
|
||||
urlWebSocket.percentEncodedQuery = urlWebSocket.percentEncodedQuery! + engineIOParam
|
||||
}
|
||||
|
||||
if !urlPolling.percentEncodedQuery!.contains("EIO") {
|
||||
urlPolling.percentEncodedQuery = urlPolling.percentEncodedQuery! + engineIOParam
|
||||
}
|
||||
|
||||
return (urlPolling.url!, urlWebSocket.url!)
|
||||
}
|
||||
|
||||
private func createWebSocketAndConnect() {
|
||||
var req = URLRequest(url: urlWebSocketWithSid)
|
||||
|
||||
addHeaders(
|
||||
to: &req,
|
||||
includingCookies: session?.configuration.httpCookieStorage?.cookies(for: urlPollingWithSid)
|
||||
)
|
||||
|
||||
ws = WebSocket(request: req, certPinner: certPinner, compressionHandler: compress ? WSCompression() : nil, useCustomEngine: useCustomEngine)
|
||||
ws?.callbackQueue = engineQueue
|
||||
ws?.delegate = self
|
||||
|
||||
ws?.connect()
|
||||
}
|
||||
|
||||
/// Called when an error happens during execution. Causes a disconnection.
|
||||
open func didError(reason: String) {
|
||||
DefaultSocketLogger.Logger.error("\(reason)", type: SocketEngine.logType)
|
||||
client?.engineDidError(reason: reason)
|
||||
disconnect(reason: reason)
|
||||
}
|
||||
|
||||
/// Disconnects from the server.
|
||||
///
|
||||
/// - parameter reason: The reason for the disconnection. This is communicated up to the client.
|
||||
open func disconnect(reason: String) {
|
||||
engineQueue.async {
|
||||
self._disconnect(reason: reason)
|
||||
}
|
||||
}
|
||||
|
||||
private func _disconnect(reason: String) {
|
||||
guard connected && !closed else { return closeOutEngine(reason: reason) }
|
||||
|
||||
DefaultSocketLogger.Logger.log("Engine is being closed.", type: SocketEngine.logType)
|
||||
|
||||
if polling {
|
||||
disconnectPolling(reason: reason)
|
||||
} else {
|
||||
sendWebSocketMessage("", withType: .close, withData: [], completion: nil)
|
||||
closeOutEngine(reason: reason)
|
||||
}
|
||||
}
|
||||
|
||||
// We need to take special care when we're polling that we send it ASAP
|
||||
// Also make sure we're on the emitQueue since we're touching postWait
|
||||
private func disconnectPolling(reason: String) {
|
||||
postWait.append((String(SocketEnginePacketType.close.rawValue), {}))
|
||||
|
||||
doRequest(for: createRequestForPostWithPostWait()) {_, _, _ in }
|
||||
closeOutEngine(reason: reason)
|
||||
}
|
||||
|
||||
/// Called to switch from HTTP long-polling to WebSockets. After calling this method the engine will be in
|
||||
/// WebSocket mode.
|
||||
///
|
||||
/// **You shouldn't call this directly**
|
||||
open func doFastUpgrade() {
|
||||
if waitingForPoll {
|
||||
DefaultSocketLogger.Logger.error("Outstanding poll when switched to WebSockets," +
|
||||
"we'll probably disconnect soon. You should report this.", type: SocketEngine.logType)
|
||||
}
|
||||
|
||||
DefaultSocketLogger.Logger.log("Switching to WebSockets", type: SocketEngine.logType)
|
||||
|
||||
sendWebSocketMessage("", withType: .upgrade, withData: [], completion: nil)
|
||||
polling = false
|
||||
fastUpgrade = false
|
||||
probing = false
|
||||
flushProbeWait()
|
||||
|
||||
// Need to flush postWait to socket since it connected successfully
|
||||
// moved from flushProbeWait() since it is also called on connected failure, and we don't want to try and send
|
||||
// packets through WebSockets when WebSockets has failed!
|
||||
if !postWait.isEmpty {
|
||||
flushWaitingForPostToWebSocket()
|
||||
}
|
||||
}
|
||||
|
||||
private func flushProbeWait() {
|
||||
DefaultSocketLogger.Logger.log("Flushing probe wait", type: SocketEngine.logType)
|
||||
|
||||
for waiter in probeWait {
|
||||
write(waiter.msg, withType: waiter.type, withData: waiter.data, completion: waiter.completion)
|
||||
}
|
||||
|
||||
probeWait.removeAll(keepingCapacity: false)
|
||||
}
|
||||
|
||||
/// Causes any packets that were waiting for POSTing to be sent through the WebSocket. This happens because when
|
||||
/// the engine is attempting to upgrade to WebSocket it does not do any POSTing.
|
||||
///
|
||||
/// **You shouldn't call this directly**
|
||||
open func flushWaitingForPostToWebSocket() {
|
||||
guard let ws = self.ws else { return }
|
||||
|
||||
for msg in postWait {
|
||||
ws.write(string: msg.msg, completion: msg.completion)
|
||||
}
|
||||
|
||||
postWait.removeAll(keepingCapacity: false)
|
||||
}
|
||||
|
||||
private func handleClose(_ reason: String) {
|
||||
client?.engineDidClose(reason: reason)
|
||||
}
|
||||
|
||||
private func handleMessage(_ message: String) {
|
||||
client?.parseEngineMessage(message)
|
||||
}
|
||||
|
||||
private func handleNOOP() {
|
||||
doPoll()
|
||||
}
|
||||
|
||||
private func handleOpen(openData: String) {
|
||||
guard let json = try? openData.toDictionary() else {
|
||||
didError(reason: "Error parsing open packet")
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
guard let sid = json["sid"] as? String else {
|
||||
didError(reason: "Open packet contained no sid")
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
let upgradeWs: Bool
|
||||
|
||||
self.sid = sid
|
||||
connected = true
|
||||
pongsMissed = 0
|
||||
|
||||
if let upgrades = json["upgrades"] as? [String] {
|
||||
upgradeWs = upgrades.contains("websocket")
|
||||
} else {
|
||||
upgradeWs = false
|
||||
}
|
||||
|
||||
if let pingInterval = json["pingInterval"] as? Int, let pingTimeout = json["pingTimeout"] as? Int {
|
||||
self.pingInterval = pingInterval
|
||||
self.pingTimeout = pingTimeout
|
||||
}
|
||||
|
||||
if !forcePolling && !forceWebsockets && upgradeWs {
|
||||
createWebSocketAndConnect()
|
||||
}
|
||||
|
||||
if version.rawValue >= 3 {
|
||||
checkPings()
|
||||
} else {
|
||||
sendPing()
|
||||
}
|
||||
|
||||
if !forceWebsockets {
|
||||
doPoll()
|
||||
}
|
||||
|
||||
client?.engineDidOpen(reason: "Connect")
|
||||
}
|
||||
|
||||
private func handlePong(with message: String) {
|
||||
pongsMissed = 0
|
||||
|
||||
// We should upgrade
|
||||
if message == "3probe" {
|
||||
DefaultSocketLogger.Logger.log("Received probe response, should upgrade to WebSockets",
|
||||
type: SocketEngine.logType)
|
||||
|
||||
upgradeTransport()
|
||||
}
|
||||
|
||||
client?.engineDidReceivePong()
|
||||
}
|
||||
|
||||
private func handlePing(with message: String) {
|
||||
if version.rawValue >= 3 {
|
||||
write("", withType: .pong, withData: [])
|
||||
}
|
||||
|
||||
client?.engineDidReceivePing()
|
||||
}
|
||||
|
||||
private func checkPings() {
|
||||
let pingInterval = self.pingInterval ?? 25_000
|
||||
let deadlineMs = Double(pingInterval + pingTimeout) / 1000
|
||||
let timeoutDeadline = DispatchTime.now() + .milliseconds(pingInterval + pingTimeout)
|
||||
|
||||
engineQueue.asyncAfter(deadline: timeoutDeadline) {[weak self, id = self.sid] in
|
||||
// Make sure not to ping old connections
|
||||
guard let this = self, this.sid == id else { return }
|
||||
|
||||
if abs(this.lastCommunication?.timeIntervalSinceNow ?? deadlineMs) >= deadlineMs {
|
||||
this.closeOutEngine(reason: "Ping timeout")
|
||||
} else {
|
||||
this.checkPings()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Parses raw binary received from engine.io.
|
||||
///
|
||||
/// - parameter data: The data to parse.
|
||||
open func parseEngineData(_ data: Data) {
|
||||
DefaultSocketLogger.Logger.log("Got binary data: \(data)", type: SocketEngine.logType)
|
||||
|
||||
lastCommunication = Date()
|
||||
|
||||
client?.parseEngineBinaryData(version.rawValue >= 3 ? data : data.subdata(in: 1..<data.endIndex))
|
||||
}
|
||||
|
||||
/// Parses a raw engine.io packet.
|
||||
///
|
||||
/// - parameter message: The message to parse.
|
||||
open func parseEngineMessage(_ message: String) {
|
||||
lastCommunication = Date()
|
||||
|
||||
DefaultSocketLogger.Logger.log("Got message: \(message)", type: SocketEngine.logType)
|
||||
|
||||
if message.hasPrefix(version.rawValue >= 3 ? "b" : "b4") {
|
||||
return handleBase64(message: message)
|
||||
}
|
||||
|
||||
guard let type = SocketEnginePacketType(rawValue: message.first?.wholeNumberValue ?? -1) else {
|
||||
checkAndHandleEngineError(message)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
switch type {
|
||||
case .message:
|
||||
handleMessage(String(message.dropFirst()))
|
||||
case .noop:
|
||||
handleNOOP()
|
||||
case .ping:
|
||||
handlePing(with: message)
|
||||
case .pong:
|
||||
handlePong(with: message)
|
||||
case .open:
|
||||
handleOpen(openData: String(message.dropFirst()))
|
||||
case .close:
|
||||
handleClose(message)
|
||||
default:
|
||||
DefaultSocketLogger.Logger.log("Got unknown packet type", type: SocketEngine.logType)
|
||||
}
|
||||
}
|
||||
|
||||
// Puts the engine back in its default state
|
||||
private func resetEngine() {
|
||||
let queue = OperationQueue()
|
||||
queue.underlyingQueue = engineQueue
|
||||
|
||||
closed = false
|
||||
connected = false
|
||||
fastUpgrade = false
|
||||
polling = true
|
||||
probing = false
|
||||
invalidated = false
|
||||
session = Foundation.URLSession(configuration: .default, delegate: sessionDelegate, delegateQueue: queue)
|
||||
sid = ""
|
||||
waitingForPoll = false
|
||||
waitingForPost = false
|
||||
}
|
||||
|
||||
private func sendPing() {
|
||||
guard connected, let pingInterval = pingInterval else {
|
||||
return
|
||||
}
|
||||
|
||||
// Server is not responding
|
||||
if pongsMissed > pongsMissedMax {
|
||||
closeOutEngine(reason: "Ping timeout")
|
||||
return
|
||||
}
|
||||
|
||||
pongsMissed += 1
|
||||
write("", withType: .ping, withData: [], completion: nil)
|
||||
|
||||
engineQueue.asyncAfter(deadline: .now() + .milliseconds(pingInterval)) {[weak self, id = self.sid] in
|
||||
// Make sure not to ping old connections
|
||||
guard let this = self, this.sid == id else {
|
||||
return
|
||||
}
|
||||
|
||||
this.sendPing()
|
||||
}
|
||||
|
||||
client?.engineDidSendPing()
|
||||
}
|
||||
|
||||
/// Called when the engine should set/update its configs from a given configuration.
|
||||
///
|
||||
/// parameter config: The `SocketIOClientConfiguration` that should be used to set/update configs.
|
||||
open func setConfigs(_ config: SocketIOClientConfiguration) {
|
||||
for option in config {
|
||||
switch option {
|
||||
case let .connectParams(params):
|
||||
connectParams = params
|
||||
case let .cookies(cookies):
|
||||
self.cookies = cookies
|
||||
case let .extraHeaders(headers):
|
||||
extraHeaders = headers
|
||||
case let .sessionDelegate(delegate):
|
||||
sessionDelegate = delegate
|
||||
case let .forcePolling(force):
|
||||
forcePolling = force
|
||||
case let .forceWebsockets(force):
|
||||
forceWebsockets = force
|
||||
case let .path(path):
|
||||
socketPath = path
|
||||
|
||||
if !socketPath.hasSuffix("/") {
|
||||
socketPath += "/"
|
||||
}
|
||||
case let .secure(secure):
|
||||
self.secure = secure
|
||||
case let .selfSigned(selfSigned):
|
||||
self.selfSigned = selfSigned
|
||||
case let .security(pinner):
|
||||
self.certPinner = pinner
|
||||
case .compress:
|
||||
self.compress = true
|
||||
case .enableSOCKSProxy:
|
||||
self.enableSOCKSProxy = true
|
||||
case let .useCustomEngine(enable):
|
||||
self.useCustomEngine = enable
|
||||
case let .version(num):
|
||||
version = num
|
||||
default:
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Moves from long-polling to websockets
|
||||
private func upgradeTransport() {
|
||||
if wsConnected {
|
||||
DefaultSocketLogger.Logger.log("Upgrading transport to WebSockets", type: SocketEngine.logType)
|
||||
|
||||
fastUpgrade = true
|
||||
sendPollMessage("", withType: .noop, withData: [], completion: nil)
|
||||
// After this point, we should not send anymore polling messages
|
||||
}
|
||||
}
|
||||
|
||||
/// Writes a message to engine.io, independent of transport.
|
||||
///
|
||||
/// - parameter msg: The message to send.
|
||||
/// - parameter type: The type of this message.
|
||||
/// - parameter data: Any data that this message has.
|
||||
/// - parameter completion: Callback called on transport write completion.
|
||||
open func write(_ msg: String, withType type: SocketEnginePacketType, withData data: [Data], completion: (() -> ())? = nil) {
|
||||
engineQueue.async {
|
||||
guard self.connected else {
|
||||
completion?()
|
||||
return
|
||||
}
|
||||
|
||||
guard !self.probing else {
|
||||
self.probeWait.append((msg, type, data, completion))
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
if self.polling {
|
||||
DefaultSocketLogger.Logger.log("Writing poll: \(msg) has data: \(data.count != 0)",
|
||||
type: SocketEngine.logType)
|
||||
self.sendPollMessage(msg, withType: type, withData: data, completion: completion)
|
||||
} else {
|
||||
DefaultSocketLogger.Logger.log("Writing ws: \(msg) has data: \(data.count != 0)",
|
||||
type: SocketEngine.logType)
|
||||
self.sendWebSocketMessage(msg, withType: type, withData: data, completion: completion)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// WebSocket Methods
|
||||
|
||||
private func websocketDidConnect() {
|
||||
if !forceWebsockets {
|
||||
probing = true
|
||||
probeWebSocket()
|
||||
} else {
|
||||
connected = true
|
||||
probing = false
|
||||
polling = false
|
||||
}
|
||||
}
|
||||
|
||||
private func websocketDidDisconnect(error: Error?) {
|
||||
probing = false
|
||||
|
||||
if closed {
|
||||
client?.engineDidClose(reason: "Disconnect")
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
guard !polling else {
|
||||
flushProbeWait()
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
connected = false
|
||||
polling = true
|
||||
|
||||
if let error = error as? WSError {
|
||||
didError(reason: "\(error.message). code=\(error.code), type=\(error.type)")
|
||||
} else if let reason = error?.localizedDescription {
|
||||
didError(reason: reason)
|
||||
} else {
|
||||
client?.engineDidClose(reason: "Socket Disconnected")
|
||||
}
|
||||
}
|
||||
|
||||
// Test Properties
|
||||
|
||||
func setConnected(_ value: Bool) {
|
||||
connected = value
|
||||
}
|
||||
}
|
||||
|
||||
extension SocketEngine {
|
||||
// MARK: URLSessionDelegate methods
|
||||
|
||||
/// Delegate called when the session becomes invalid.
|
||||
public func URLSession(session: URLSession, didBecomeInvalidWithError error: NSError?) {
|
||||
DefaultSocketLogger.Logger.error("Engine URLSession became invalid", type: "SocketEngine")
|
||||
|
||||
didError(reason: "Engine URLSession became invalid")
|
||||
}
|
||||
}
|
||||
|
||||
enum EngineError: Error {
|
||||
case canceled
|
||||
}
|
||||
|
||||
extension SocketEngine {
|
||||
/// Delegate method for WebSocketDelegate.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - event: WS Event
|
||||
/// - _:
|
||||
public func didReceive(event: Starscream.WebSocketEvent, client: Starscream.WebSocketClient) {
|
||||
switch event {
|
||||
case let .connected(headers):
|
||||
wsConnected = true
|
||||
self.client?.engineDidWebsocketUpgrade(headers: headers)
|
||||
websocketDidConnect()
|
||||
case .cancelled:
|
||||
wsConnected = false
|
||||
websocketDidDisconnect(error: EngineError.canceled)
|
||||
case .disconnected(_, _):
|
||||
wsConnected = false
|
||||
websocketDidDisconnect(error: nil)
|
||||
case .viabilityChanged(false):
|
||||
wsConnected = false
|
||||
websocketDidDisconnect(error: nil)
|
||||
case .peerClosed:
|
||||
wsConnected = false
|
||||
websocketDidDisconnect(error: nil)
|
||||
case let .text(msg):
|
||||
parseEngineMessage(msg)
|
||||
case let .binary(data):
|
||||
parseEngineData(data)
|
||||
case _:
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
73
Source/SocketIO/Engine/SocketEngineClient.swift
Normal file
73
Source/SocketIO/Engine/SocketEngineClient.swift
Normal file
@ -0,0 +1,73 @@
|
||||
//
|
||||
// SocketEngineClient.swift
|
||||
// Socket.IO-Client-Swift
|
||||
//
|
||||
// Created by Erik Little on 3/19/15.
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
/// Declares that a type will be a delegate to an engine.
|
||||
@objc public protocol SocketEngineClient {
|
||||
// MARK: Methods
|
||||
|
||||
/// Called when the engine errors.
|
||||
///
|
||||
/// - parameter reason: The reason the engine errored.
|
||||
func engineDidError(reason: String)
|
||||
|
||||
/// Called when the engine closes.
|
||||
///
|
||||
/// - parameter reason: The reason that the engine closed.
|
||||
func engineDidClose(reason: String)
|
||||
|
||||
/// Called when the engine opens.
|
||||
///
|
||||
/// - parameter reason: The reason the engine opened.
|
||||
func engineDidOpen(reason: String)
|
||||
|
||||
/// Called when the engine receives a ping message. Only called in socket.io >3.
|
||||
func engineDidReceivePing()
|
||||
|
||||
/// Called when the engine receives a pong message. Only called in socket.io 2.
|
||||
func engineDidReceivePong()
|
||||
|
||||
/// Called when the engine sends a ping to the server. Only called in socket.io 2.
|
||||
func engineDidSendPing()
|
||||
|
||||
/// Called when the engine sends a pong to the server. Only called in socket.io >3.
|
||||
func engineDidSendPong()
|
||||
|
||||
/// Called when the engine has a message that must be parsed.
|
||||
///
|
||||
/// - parameter msg: The message that needs parsing.
|
||||
func parseEngineMessage(_ msg: String)
|
||||
|
||||
/// Called when the engine receives binary data.
|
||||
///
|
||||
/// - parameter data: The data the engine received.
|
||||
func parseEngineBinaryData(_ data: Data)
|
||||
|
||||
/// Called when when upgrading the http connection to a websocket connection.
|
||||
///
|
||||
/// - parameter headers: The http headers.
|
||||
func engineDidWebsocketUpgrade(headers: [String: String])
|
||||
}
|
||||
@ -25,6 +25,26 @@
|
||||
|
||||
import Foundation
|
||||
|
||||
@objc public enum SocketEnginePacketType : Int {
|
||||
case Open, Close, Ping, Pong, Message, Upgrade, Noop
|
||||
}
|
||||
/// Represents the type of engine.io packet types.
|
||||
@objc public enum SocketEnginePacketType: Int {
|
||||
/// Open message.
|
||||
case open
|
||||
|
||||
/// Close message.
|
||||
case close
|
||||
|
||||
/// Ping message.
|
||||
case ping
|
||||
|
||||
/// Pong message.
|
||||
case pong
|
||||
|
||||
/// Regular message.
|
||||
case message
|
||||
|
||||
/// Upgrade message.
|
||||
case upgrade
|
||||
|
||||
/// NOOP.
|
||||
case noop
|
||||
}
|
||||
262
Source/SocketIO/Engine/SocketEnginePollable.swift
Normal file
262
Source/SocketIO/Engine/SocketEnginePollable.swift
Normal file
@ -0,0 +1,262 @@
|
||||
//
|
||||
// SocketEnginePollable.swift
|
||||
// Socket.IO-Client-Swift
|
||||
//
|
||||
// Created by Erik Little on 1/15/16.
|
||||
//
|
||||
// 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.
|
||||
|
||||
import Foundation
|
||||
|
||||
/// Protocol that is used to implement socket.io polling support
|
||||
public protocol SocketEnginePollable: SocketEngineSpec {
|
||||
// MARK: Properties
|
||||
|
||||
/// `true` If engine's session has been invalidated.
|
||||
var invalidated: Bool { get }
|
||||
|
||||
/// A queue of engine.io messages waiting for POSTing
|
||||
///
|
||||
/// **You should not touch this directly**
|
||||
var postWait: [Post] { get set }
|
||||
|
||||
/// The URLSession that will be used for polling.
|
||||
var session: URLSession? { get }
|
||||
|
||||
/// `true` if there is an outstanding poll. Trying to poll before the first is done will cause socket.io to
|
||||
/// disconnect us.
|
||||
///
|
||||
/// **Do not touch this directly**
|
||||
var waitingForPoll: Bool { get set }
|
||||
|
||||
/// `true` if there is an outstanding post. Trying to post before the first is done will cause socket.io to
|
||||
/// disconnect us.
|
||||
///
|
||||
/// **Do not touch this directly**
|
||||
var waitingForPost: Bool { get set }
|
||||
|
||||
// MARK: Methods
|
||||
|
||||
/// Call to send a long-polling request.
|
||||
///
|
||||
/// You shouldn't need to call this directly, the engine should automatically maintain a long-poll request.
|
||||
func doPoll()
|
||||
|
||||
/// Sends an engine.io message through the polling transport.
|
||||
///
|
||||
/// You shouldn't call this directly, instead call the `write` method on `SocketEngine`.
|
||||
///
|
||||
/// - parameter message: The message to send.
|
||||
/// - parameter withType: The type of message to send.
|
||||
/// - parameter withData: The data associated with this message.
|
||||
func sendPollMessage(_ message: String, withType type: SocketEnginePacketType, withData datas: [Data], completion: (() -> ())?)
|
||||
|
||||
/// Call to stop polling and invalidate the URLSession.
|
||||
func stopPolling()
|
||||
}
|
||||
|
||||
// Default polling methods
|
||||
extension SocketEnginePollable {
|
||||
func createRequestForPostWithPostWait() -> URLRequest {
|
||||
defer {
|
||||
for packet in postWait { packet.completion?() }
|
||||
postWait.removeAll(keepingCapacity: true)
|
||||
}
|
||||
|
||||
var postStr = ""
|
||||
|
||||
if version.rawValue >= 3 {
|
||||
postStr = postWait.lazy.map({ $0.msg }).joined(separator: "\u{1e}")
|
||||
} else {
|
||||
for packet in postWait {
|
||||
postStr += "\(packet.msg.utf16.count):\(packet.msg)"
|
||||
}
|
||||
}
|
||||
|
||||
DefaultSocketLogger.Logger.log("Created POST string: \(postStr)", type: "SocketEnginePolling")
|
||||
|
||||
var req = URLRequest(url: urlPollingWithSid)
|
||||
let postData = postStr.data(using: .utf8, allowLossyConversion: false)!
|
||||
|
||||
addHeaders(to: &req)
|
||||
|
||||
req.httpMethod = "POST"
|
||||
req.setValue("text/plain; charset=UTF-8", forHTTPHeaderField: "Content-Type")
|
||||
req.httpBody = postData
|
||||
req.setValue(String(postData.count), forHTTPHeaderField: "Content-Length")
|
||||
|
||||
return req
|
||||
}
|
||||
|
||||
/// Call to send a long-polling request.
|
||||
///
|
||||
/// You shouldn't need to call this directly, the engine should automatically maintain a long-poll request.
|
||||
public func doPoll() {
|
||||
guard polling && !waitingForPoll && connected && !closed else { return }
|
||||
|
||||
var req = URLRequest(url: urlPollingWithSid)
|
||||
addHeaders(to: &req)
|
||||
|
||||
doLongPoll(for: req)
|
||||
}
|
||||
|
||||
func doRequest(for req: URLRequest, callbackWith callback: @escaping (Data?, URLResponse?, Error?) -> ()) {
|
||||
guard polling && !closed && !invalidated && !fastUpgrade else { return }
|
||||
|
||||
DefaultSocketLogger.Logger.log("Doing polling \(req.httpMethod ?? "") \(req)", type: "SocketEnginePolling")
|
||||
|
||||
session?.dataTask(with: req, completionHandler: callback).resume()
|
||||
}
|
||||
|
||||
func doLongPoll(for req: URLRequest) {
|
||||
waitingForPoll = true
|
||||
|
||||
doRequest(for: req) {[weak self] data, res, err in
|
||||
guard let this = self, this.polling else { return }
|
||||
guard let data = data, let res = res as? HTTPURLResponse, res.statusCode == 200 else {
|
||||
if let err = err {
|
||||
DefaultSocketLogger.Logger.error(err.localizedDescription, type: "SocketEnginePolling")
|
||||
} else {
|
||||
DefaultSocketLogger.Logger.error("Error during long poll request", type: "SocketEnginePolling")
|
||||
}
|
||||
|
||||
if this.polling {
|
||||
this.didError(reason: err?.localizedDescription ?? "Error")
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
DefaultSocketLogger.Logger.log("Got polling response", type: "SocketEnginePolling")
|
||||
|
||||
if let str = String(data: data, encoding: .utf8) {
|
||||
this.parsePollingMessage(str)
|
||||
}
|
||||
|
||||
this.waitingForPoll = false
|
||||
|
||||
if this.fastUpgrade {
|
||||
this.doFastUpgrade()
|
||||
} else if !this.closed && this.polling {
|
||||
this.doPoll()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func flushWaitingForPost() {
|
||||
guard postWait.count != 0 && connected else { return }
|
||||
guard polling else {
|
||||
flushWaitingForPostToWebSocket()
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
let req = createRequestForPostWithPostWait()
|
||||
|
||||
waitingForPost = true
|
||||
|
||||
DefaultSocketLogger.Logger.log("POSTing", type: "SocketEnginePolling")
|
||||
|
||||
doRequest(for: req) {[weak self] _, res, err in
|
||||
guard let this = self else { return }
|
||||
guard let res = res as? HTTPURLResponse, res.statusCode == 200 else {
|
||||
if let err = err {
|
||||
DefaultSocketLogger.Logger.error(err.localizedDescription, type: "SocketEnginePolling")
|
||||
} else {
|
||||
DefaultSocketLogger.Logger.error("Error flushing waiting posts", type: "SocketEnginePolling")
|
||||
}
|
||||
|
||||
if this.polling {
|
||||
this.didError(reason: err?.localizedDescription ?? "Error")
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
this.waitingForPost = false
|
||||
|
||||
if !this.fastUpgrade {
|
||||
this.flushWaitingForPost()
|
||||
this.doPoll()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func parsePollingMessage(_ str: String) {
|
||||
guard !str.isEmpty else { return }
|
||||
|
||||
DefaultSocketLogger.Logger.log("Got poll message: \(str)", type: "SocketEnginePolling")
|
||||
|
||||
if version.rawValue >= 3 {
|
||||
let records = str.components(separatedBy: "\u{1e}")
|
||||
|
||||
for record in records {
|
||||
parseEngineMessage(record)
|
||||
}
|
||||
} else {
|
||||
guard str.count != 1 else {
|
||||
parseEngineMessage(str)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
var reader = SocketStringReader(message: str)
|
||||
|
||||
while reader.hasNext {
|
||||
if let n = Int(reader.readUntilOccurence(of: ":")) {
|
||||
parseEngineMessage(reader.read(count: n))
|
||||
} else {
|
||||
parseEngineMessage(str)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Sends an engine.io message through the polling transport.
|
||||
///
|
||||
/// You shouldn't call this directly, instead call the `write` method on `SocketEngine`.
|
||||
///
|
||||
/// - parameter message: The message to send.
|
||||
/// - parameter withType: The type of message to send.
|
||||
/// - parameter withData: The data associated with this message.
|
||||
/// - parameter completion: Callback called on transport write completion.
|
||||
public func sendPollMessage(_ message: String, withType type: SocketEnginePacketType, withData datas: [Data], completion: (() -> ())? = nil) {
|
||||
DefaultSocketLogger.Logger.log("Sending poll: \(message) as type: \(type.rawValue)", type: "SocketEnginePolling")
|
||||
|
||||
postWait.append((String(type.rawValue) + message, completion))
|
||||
|
||||
for data in datas {
|
||||
if case let .right(bin) = createBinaryDataForSend(using: data) {
|
||||
postWait.append((bin, {}))
|
||||
}
|
||||
}
|
||||
|
||||
if !waitingForPost {
|
||||
flushWaitingForPost()
|
||||
}
|
||||
}
|
||||
|
||||
/// Call to stop polling and invalidate the URLSession.
|
||||
public func stopPolling() {
|
||||
waitingForPoll = false
|
||||
waitingForPost = false
|
||||
session?.finishTasksAndInvalidate()
|
||||
}
|
||||
}
|
||||
209
Source/SocketIO/Engine/SocketEngineSpec.swift
Normal file
209
Source/SocketIO/Engine/SocketEngineSpec.swift
Normal file
@ -0,0 +1,209 @@
|
||||
//
|
||||
// SocketEngineSpec.swift
|
||||
// Socket.IO-Client-Swift
|
||||
//
|
||||
// Created by Erik Little on 10/7/15.
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import Starscream
|
||||
|
||||
/// Specifies a SocketEngine.
|
||||
public protocol SocketEngineSpec: AnyObject {
|
||||
// MARK: Properties
|
||||
|
||||
/// The client for this engine.
|
||||
var client: SocketEngineClient? { get set }
|
||||
|
||||
/// `true` if this engine is closed.
|
||||
var closed: Bool { get }
|
||||
|
||||
/// If `true` the engine will attempt to use WebSocket compression.
|
||||
var compress: Bool { get }
|
||||
|
||||
/// `true` if this engine is connected. Connected means that the initial poll connect has succeeded.
|
||||
var connected: Bool { get }
|
||||
|
||||
/// The connect parameters sent during a connect.
|
||||
var connectParams: [String: Any]? { get set }
|
||||
|
||||
/// An array of HTTPCookies that are sent during the connection.
|
||||
var cookies: [HTTPCookie]? { get }
|
||||
|
||||
/// The queue that all engine actions take place on.
|
||||
var engineQueue: DispatchQueue { get }
|
||||
|
||||
/// A dictionary of extra http headers that will be set during connection.
|
||||
var extraHeaders: [String: String]? { get set }
|
||||
|
||||
/// When `true`, the engine is in the process of switching to WebSockets.
|
||||
var fastUpgrade: Bool { get }
|
||||
|
||||
/// When `true`, the engine will only use HTTP long-polling as a transport.
|
||||
var forcePolling: Bool { get }
|
||||
|
||||
/// When `true`, the engine will only use WebSockets as a transport.
|
||||
var forceWebsockets: Bool { get }
|
||||
|
||||
/// If `true`, the engine is currently in HTTP long-polling mode.
|
||||
var polling: Bool { get }
|
||||
|
||||
/// If `true`, the engine is currently seeing whether it can upgrade to WebSockets.
|
||||
var probing: Bool { get }
|
||||
|
||||
/// The session id for this engine.
|
||||
var sid: String { get }
|
||||
|
||||
/// The path to engine.io.
|
||||
var socketPath: String { get }
|
||||
|
||||
/// The url for polling.
|
||||
var urlPolling: URL { get }
|
||||
|
||||
/// The url for WebSockets.
|
||||
var urlWebSocket: URL { get }
|
||||
|
||||
/// The version of engine.io being used. Default is three.
|
||||
var version: SocketIOVersion { get }
|
||||
|
||||
/// If `true`, then the engine is currently in WebSockets mode.
|
||||
@available(*, deprecated, message: "No longer needed, if we're not polling, then we must be doing websockets")
|
||||
var websocket: Bool { get }
|
||||
|
||||
/// The WebSocket for this engine.
|
||||
var ws: WebSocket? { get }
|
||||
|
||||
// MARK: Initializers
|
||||
|
||||
/// Creates a new engine.
|
||||
///
|
||||
/// - parameter client: The client for this engine.
|
||||
/// - parameter url: The url for this engine.
|
||||
/// - parameter options: The options for this engine.
|
||||
init(client: SocketEngineClient, url: URL, options: [String: Any]?)
|
||||
|
||||
// MARK: Methods
|
||||
|
||||
/// Starts the connection to the server.
|
||||
func connect()
|
||||
|
||||
/// Called when an error happens during execution. Causes a disconnection.
|
||||
func didError(reason: String)
|
||||
|
||||
/// Disconnects from the server.
|
||||
///
|
||||
/// - parameter reason: The reason for the disconnection. This is communicated up to the client.
|
||||
func disconnect(reason: String)
|
||||
|
||||
/// Called to switch from HTTP long-polling to WebSockets. After calling this method the engine will be in
|
||||
/// WebSocket mode.
|
||||
///
|
||||
/// **You shouldn't call this directly**
|
||||
func doFastUpgrade()
|
||||
|
||||
/// Causes any packets that were waiting for POSTing to be sent through the WebSocket. This happens because when
|
||||
/// the engine is attempting to upgrade to WebSocket it does not do any POSTing.
|
||||
///
|
||||
/// **You shouldn't call this directly**
|
||||
func flushWaitingForPostToWebSocket()
|
||||
|
||||
/// Parses raw binary received from engine.io.
|
||||
///
|
||||
/// - parameter data: The data to parse.
|
||||
func parseEngineData(_ data: Data)
|
||||
|
||||
/// Parses a raw engine.io packet.
|
||||
///
|
||||
/// - parameter message: The message to parse.
|
||||
func parseEngineMessage(_ message: String)
|
||||
|
||||
/// Writes a message to engine.io, independent of transport.
|
||||
///
|
||||
/// - parameter msg: The message to send.
|
||||
/// - parameter type: The type of this message.
|
||||
/// - parameter data: Any data that this message has.
|
||||
/// - parameter completion: Callback called on transport write completion.
|
||||
func write(_ msg: String, withType type: SocketEnginePacketType, withData data: [Data], completion: (() -> ())?)
|
||||
}
|
||||
|
||||
extension SocketEngineSpec {
|
||||
var engineIOParam: String {
|
||||
switch version {
|
||||
case .two:
|
||||
return "&EIO=3"
|
||||
case .three:
|
||||
return "&EIO=4"
|
||||
}
|
||||
}
|
||||
|
||||
var urlPollingWithSid: URL {
|
||||
var com = URLComponents(url: urlPolling, resolvingAgainstBaseURL: false)!
|
||||
com.percentEncodedQuery = com.percentEncodedQuery! + "&sid=\(sid.urlEncode()!)"
|
||||
|
||||
if !com.percentEncodedQuery!.contains("EIO") {
|
||||
com.percentEncodedQuery = com.percentEncodedQuery! + engineIOParam
|
||||
}
|
||||
|
||||
return com.url!
|
||||
}
|
||||
|
||||
var urlWebSocketWithSid: URL {
|
||||
var com = URLComponents(url: urlWebSocket, resolvingAgainstBaseURL: false)!
|
||||
com.percentEncodedQuery = com.percentEncodedQuery! + (sid == "" ? "" : "&sid=\(sid.urlEncode()!)")
|
||||
|
||||
if !com.percentEncodedQuery!.contains("EIO") {
|
||||
com.percentEncodedQuery = com.percentEncodedQuery! + engineIOParam
|
||||
}
|
||||
|
||||
|
||||
return com.url!
|
||||
}
|
||||
|
||||
func addHeaders(to req: inout URLRequest, includingCookies additionalCookies: [HTTPCookie]? = nil) {
|
||||
var cookiesToAdd: [HTTPCookie] = cookies ?? []
|
||||
cookiesToAdd += additionalCookies ?? []
|
||||
|
||||
if !cookiesToAdd.isEmpty {
|
||||
req.allHTTPHeaderFields = HTTPCookie.requestHeaderFields(with: cookiesToAdd)
|
||||
}
|
||||
|
||||
if let extraHeaders = extraHeaders {
|
||||
for (headerName, value) in extraHeaders {
|
||||
req.setValue(value, forHTTPHeaderField: headerName)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func createBinaryDataForSend(using data: Data) -> Either<Data, String> {
|
||||
let prefixB64 = version.rawValue >= 3 ? "b" : "b4"
|
||||
|
||||
if polling {
|
||||
return .right(prefixB64 + data.base64EncodedString(options: Data.Base64EncodingOptions(rawValue: 0)))
|
||||
} else {
|
||||
return .left(version.rawValue >= 3 ? data : Data([0x4]) + data)
|
||||
}
|
||||
}
|
||||
|
||||
/// Send an engine message (4)
|
||||
func send(_ msg: String, withData datas: [Data], completion: (() -> ())? = nil) {
|
||||
write(msg, withType: .message, withData: datas, completion: completion)
|
||||
}
|
||||
}
|
||||
87
Source/SocketIO/Engine/SocketEngineWebsocket.swift
Normal file
87
Source/SocketIO/Engine/SocketEngineWebsocket.swift
Normal file
@ -0,0 +1,87 @@
|
||||
//
|
||||
// SocketEngineWebsocket.swift
|
||||
// Socket.IO-Client-Swift
|
||||
//
|
||||
// Created by Erik Little on 1/15/16.
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import Starscream
|
||||
|
||||
/// Protocol that is used to implement socket.io WebSocket support
|
||||
public protocol SocketEngineWebsocket: SocketEngineSpec {
|
||||
// MARK: Properties
|
||||
|
||||
/// Whether or not the ws is connected
|
||||
var wsConnected: Bool { get }
|
||||
|
||||
// MARK: Methods
|
||||
|
||||
/// Sends an engine.io message through the WebSocket transport.
|
||||
///
|
||||
/// You shouldn't call this directly, instead call the `write` method on `SocketEngine`.
|
||||
///
|
||||
/// - parameter message: The message to send.
|
||||
/// - parameter withType: The type of message to send.
|
||||
/// - parameter withData: The data associated with this message.
|
||||
/// - parameter completion: Callback called on transport write completion.
|
||||
func sendWebSocketMessage(_ str: String,
|
||||
withType type: SocketEnginePacketType,
|
||||
withData datas: [Data],
|
||||
completion: (() -> ())?)
|
||||
}
|
||||
|
||||
// WebSocket methods
|
||||
extension SocketEngineWebsocket {
|
||||
func probeWebSocket() {
|
||||
if wsConnected {
|
||||
sendWebSocketMessage("probe", withType: .ping, withData: [], completion: nil)
|
||||
}
|
||||
}
|
||||
|
||||
/// Sends an engine.io message through the WebSocket transport.
|
||||
///
|
||||
/// You shouldn't call this directly, instead call the `write` method on `SocketEngine`.
|
||||
///
|
||||
/// - parameter message: The message to send.
|
||||
/// - parameter withType: The type of message to send.
|
||||
/// - parameter withData: The data associated with this message.
|
||||
/// - parameter completion: Callback called on transport write completion.
|
||||
public func sendWebSocketMessage(_ str: String,
|
||||
withType type: SocketEnginePacketType,
|
||||
withData data: [Data],
|
||||
completion: (() -> ())?
|
||||
) {
|
||||
DefaultSocketLogger.Logger.log("Sending ws: \(str) as type: \(type.rawValue)", type: "SocketEngineWebSocket")
|
||||
|
||||
ws?.write(string: "\(type.rawValue)\(str)")
|
||||
|
||||
for item in data {
|
||||
if case let .left(bin) = createBinaryDataForSend(using: item) {
|
||||
ws?.write(data: bin, completion: completion)
|
||||
}
|
||||
}
|
||||
|
||||
if data.count == 0 {
|
||||
completion?()
|
||||
}
|
||||
}
|
||||
}
|
||||
613
Source/SocketIO/Manager/SocketManager.swift
Normal file
613
Source/SocketIO/Manager/SocketManager.swift
Normal file
@ -0,0 +1,613 @@
|
||||
//
|
||||
// Created by Erik Little on 10/14/17.
|
||||
//
|
||||
// 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.
|
||||
|
||||
import Dispatch
|
||||
import Foundation
|
||||
|
||||
///
|
||||
/// A manager for a socket.io connection.
|
||||
///
|
||||
/// A `SocketManager` is responsible for multiplexing multiple namespaces through a single `SocketEngineSpec`.
|
||||
///
|
||||
/// Example:
|
||||
///
|
||||
/// ```swift
|
||||
/// let manager = SocketManager(socketURL: URL(string:"http://localhost:8080/")!)
|
||||
/// let defaultNamespaceSocket = manager.defaultSocket
|
||||
/// let swiftSocket = manager.socket(forNamespace: "/swift")
|
||||
///
|
||||
/// // defaultNamespaceSocket and swiftSocket both share a single connection to the server
|
||||
/// ```
|
||||
///
|
||||
/// Sockets created through the manager are retained by the manager. So at the very least, a single strong reference
|
||||
/// to the manager must be maintained to keep sockets alive.
|
||||
///
|
||||
/// To disconnect a socket and remove it from the manager, either call `SocketIOClient.disconnect()` on the socket,
|
||||
/// or call one of the `disconnectSocket` methods on this class.
|
||||
///
|
||||
/// **NOTE**: The manager is not thread/queue safe, all interaction with the manager should be done on the `handleQueue`
|
||||
///
|
||||
open class SocketManager: NSObject, SocketManagerSpec, SocketParsable, SocketDataBufferable, ConfigSettable {
|
||||
private static let logType = "SocketManager"
|
||||
|
||||
// MARK: Properties
|
||||
|
||||
/// The socket associated with the default namespace ("/").
|
||||
public var defaultSocket: SocketIOClient {
|
||||
return socket(forNamespace: "/")
|
||||
}
|
||||
|
||||
/// The URL of the socket.io server.
|
||||
///
|
||||
/// If changed after calling `init`, `forceNew` must be set to `true`, or it will only connect to the url set in the
|
||||
/// init.
|
||||
public let socketURL: URL
|
||||
|
||||
/// The configuration for this client.
|
||||
///
|
||||
/// **Some configs will not take affect until after a reconnect if set after calling a connect method**.
|
||||
public var config: SocketIOClientConfiguration {
|
||||
get {
|
||||
return _config
|
||||
}
|
||||
|
||||
set {
|
||||
if status.active {
|
||||
DefaultSocketLogger.Logger.log("Setting configs on active manager. Some configs may not be applied until reconnect",
|
||||
type: SocketManager.logType)
|
||||
}
|
||||
|
||||
setConfigs(newValue)
|
||||
}
|
||||
}
|
||||
|
||||
/// The engine for this manager.
|
||||
public var engine: SocketEngineSpec?
|
||||
|
||||
/// If `true` then every time `connect` is called, a new engine will be created.
|
||||
public var forceNew = false
|
||||
|
||||
/// The queue that all interaction with the client should occur on. This is the queue that event handlers are
|
||||
/// called on.
|
||||
///
|
||||
/// **This should be a serial queue! Concurrent queues are not supported and might cause crashes and races**.
|
||||
public var handleQueue = DispatchQueue.main
|
||||
|
||||
/// The sockets in this manager indexed by namespace.
|
||||
public var nsps = [String: SocketIOClient]()
|
||||
|
||||
/// If `true`, this client will try and reconnect on any disconnects.
|
||||
public var reconnects = true
|
||||
|
||||
/// The minimum number of seconds to wait before attempting to reconnect.
|
||||
public var reconnectWait = 10
|
||||
|
||||
/// The maximum number of seconds to wait before attempting to reconnect.
|
||||
public var reconnectWaitMax = 30
|
||||
|
||||
/// The randomization factor for calculating reconnect jitter.
|
||||
public var randomizationFactor = 0.5
|
||||
|
||||
/// The status of this manager.
|
||||
public private(set) var status: SocketIOStatus = .notConnected {
|
||||
didSet {
|
||||
switch status {
|
||||
case .connected:
|
||||
reconnecting = false
|
||||
currentReconnectAttempt = 0
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public private(set) var version = SocketIOVersion.three
|
||||
|
||||
/// A list of packets that are waiting for binary data.
|
||||
///
|
||||
/// The way that socket.io works all data should be sent directly after each packet.
|
||||
/// So this should ideally be an array of one packet waiting for data.
|
||||
///
|
||||
/// **This should not be modified directly.**
|
||||
public var waitingPackets = [SocketPacket]()
|
||||
|
||||
private(set) var reconnectAttempts = -1
|
||||
|
||||
private var _config: SocketIOClientConfiguration
|
||||
internal var currentReconnectAttempt = 0
|
||||
private var reconnecting = false
|
||||
|
||||
// MARK: Initializers
|
||||
|
||||
/// Type safe way to create a new SocketIOClient. `opts` can be omitted.
|
||||
///
|
||||
/// - parameter socketURL: The url of the socket.io server.
|
||||
/// - parameter config: The config for this socket.
|
||||
public init(socketURL: URL, config: SocketIOClientConfiguration = []) {
|
||||
self._config = config
|
||||
self.socketURL = socketURL
|
||||
|
||||
super.init()
|
||||
|
||||
setConfigs(_config)
|
||||
}
|
||||
|
||||
/// Not so type safe way to create a SocketIOClient, meant for Objective-C compatiblity.
|
||||
/// If using Swift it's recommended to use `init(socketURL: NSURL, options: Set<SocketIOClientOption>)`
|
||||
///
|
||||
/// - parameter socketURL: The url of the socket.io server.
|
||||
/// - parameter config: The config for this socket.
|
||||
@objc
|
||||
public convenience init(socketURL: URL, config: [String: Any]?) {
|
||||
self.init(socketURL: socketURL, config: config?.toSocketConfiguration() ?? [])
|
||||
}
|
||||
|
||||
/// :nodoc:
|
||||
deinit {
|
||||
DefaultSocketLogger.Logger.log("Manager is being released", type: SocketManager.logType)
|
||||
|
||||
engine?.disconnect(reason: "Manager Deinit")
|
||||
}
|
||||
|
||||
// MARK: Methods
|
||||
|
||||
private func addEngine() {
|
||||
DefaultSocketLogger.Logger.log("Adding engine", type: SocketManager.logType)
|
||||
|
||||
engine?.engineQueue.sync {
|
||||
self.engine?.client = nil
|
||||
|
||||
// Close old engine so it will not leak because of URLSession if in polling mode
|
||||
self.engine?.disconnect(reason: "Adding new engine")
|
||||
}
|
||||
|
||||
engine = SocketEngine(client: self, url: socketURL, config: config)
|
||||
}
|
||||
|
||||
/// Connects the underlying transport and the default namespace socket.
|
||||
///
|
||||
/// Override if you wish to attach a custom `SocketEngineSpec`.
|
||||
open func connect() {
|
||||
if status == .connected || (status == .connecting && currentReconnectAttempt == 0) {
|
||||
DefaultSocketLogger.Logger.log("Tried connecting an already active socket", type: SocketManager.logType)
|
||||
return
|
||||
}
|
||||
|
||||
if engine == nil || forceNew {
|
||||
addEngine()
|
||||
}
|
||||
|
||||
status = .connecting
|
||||
|
||||
engine?.connect()
|
||||
}
|
||||
|
||||
/// Connects a socket through this manager's engine.
|
||||
///
|
||||
/// - parameter socket: The socket who we should connect through this manager.
|
||||
/// - parameter withPayload: Optional payload to send on connect
|
||||
open func connectSocket(_ socket: SocketIOClient, withPayload payload: [String: Any]? = nil) {
|
||||
guard status == .connected else {
|
||||
DefaultSocketLogger.Logger.log("Tried connecting socket when engine isn't open. Connecting",
|
||||
type: SocketManager.logType)
|
||||
|
||||
connect()
|
||||
return
|
||||
}
|
||||
|
||||
var payloadStr = ""
|
||||
|
||||
if version.rawValue >= 3 && payload != nil,
|
||||
let payloadData = try? JSONSerialization.data(withJSONObject: payload!, options: .fragmentsAllowed),
|
||||
let jsonString = String(data: payloadData, encoding: .utf8) {
|
||||
payloadStr = jsonString
|
||||
}
|
||||
|
||||
engine?.send("0\(socket.nsp),\(payloadStr)", withData: [])
|
||||
}
|
||||
|
||||
/// Called when the manager has disconnected from socket.io.
|
||||
///
|
||||
/// - parameter reason: The reason for the disconnection.
|
||||
open func didDisconnect(reason: String) {
|
||||
forAll {socket in
|
||||
socket.didDisconnect(reason: reason)
|
||||
}
|
||||
}
|
||||
|
||||
/// Disconnects the manager and all associated sockets.
|
||||
open func disconnect() {
|
||||
DefaultSocketLogger.Logger.log("Manager closing", type: SocketManager.logType)
|
||||
|
||||
status = .disconnected
|
||||
|
||||
engine?.disconnect(reason: "Disconnect")
|
||||
}
|
||||
|
||||
/// Disconnects the given socket.
|
||||
///
|
||||
/// This will remove the socket for the manager's control, and make the socket instance useless and ready for
|
||||
/// releasing.
|
||||
///
|
||||
/// - parameter socket: The socket to disconnect.
|
||||
open func disconnectSocket(_ socket: SocketIOClient) {
|
||||
engine?.send("1\(socket.nsp),", withData: [])
|
||||
|
||||
socket.didDisconnect(reason: "Namespace leave")
|
||||
}
|
||||
|
||||
/// Disconnects the socket associated with `forNamespace`.
|
||||
///
|
||||
/// This will remove the socket for the manager's control, and make the socket instance useless and ready for
|
||||
/// releasing.
|
||||
///
|
||||
/// - parameter nsp: The namespace to disconnect from.
|
||||
open func disconnectSocket(forNamespace nsp: String) {
|
||||
guard let socket = nsps.removeValue(forKey: nsp) else {
|
||||
DefaultSocketLogger.Logger.log("Could not find socket for \(nsp) to disconnect",
|
||||
type: SocketManager.logType)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
disconnectSocket(socket)
|
||||
}
|
||||
|
||||
/// Sends a client event to all sockets in `nsps`
|
||||
///
|
||||
/// - parameter clientEvent: The event to emit.
|
||||
open func emitAll(clientEvent event: SocketClientEvent, data: [Any]) {
|
||||
forAll {socket in
|
||||
socket.handleClientEvent(event, data: data)
|
||||
}
|
||||
}
|
||||
|
||||
/// Sends an event to the server on all namespaces in this manager.
|
||||
///
|
||||
/// - parameter event: The event to send.
|
||||
/// - parameter items: The data to send with this event.
|
||||
open func emitAll(_ event: String, _ items: SocketData...) {
|
||||
guard let emitData = try? items.map({ try $0.socketRepresentation() }) else {
|
||||
DefaultSocketLogger.Logger.error("Error creating socketRepresentation for emit: \(event), \(items)",
|
||||
type: SocketManager.logType)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
forAll {socket in
|
||||
socket.emit([event] + emitData)
|
||||
}
|
||||
}
|
||||
|
||||
/// Called when the engine closes.
|
||||
///
|
||||
/// - parameter reason: The reason that the engine closed.
|
||||
open func engineDidClose(reason: String) {
|
||||
handleQueue.async {
|
||||
self._engineDidClose(reason: reason)
|
||||
}
|
||||
}
|
||||
|
||||
private func _engineDidClose(reason: String) {
|
||||
waitingPackets.removeAll()
|
||||
|
||||
if status != .disconnected {
|
||||
status = .notConnected
|
||||
}
|
||||
|
||||
if status == .disconnected || !reconnects {
|
||||
didDisconnect(reason: reason)
|
||||
} else if !reconnecting {
|
||||
reconnecting = true
|
||||
tryReconnect(reason: reason)
|
||||
}
|
||||
}
|
||||
|
||||
/// Called when the engine errors.
|
||||
///
|
||||
/// - parameter reason: The reason the engine errored.
|
||||
open func engineDidError(reason: String) {
|
||||
handleQueue.async {
|
||||
self._engineDidError(reason: reason)
|
||||
}
|
||||
}
|
||||
|
||||
private func _engineDidError(reason: String) {
|
||||
DefaultSocketLogger.Logger.error("\(reason)", type: SocketManager.logType)
|
||||
|
||||
emitAll(clientEvent: .error, data: [reason])
|
||||
}
|
||||
|
||||
/// Called when the engine opens.
|
||||
///
|
||||
/// - parameter reason: The reason the engine opened.
|
||||
open func engineDidOpen(reason: String) {
|
||||
handleQueue.async {
|
||||
self._engineDidOpen(reason: reason)
|
||||
}
|
||||
}
|
||||
|
||||
private func _engineDidOpen(reason: String) {
|
||||
DefaultSocketLogger.Logger.log("Engine opened \(reason)", type: SocketManager.logType)
|
||||
|
||||
status = .connected
|
||||
|
||||
if version.rawValue < 3 {
|
||||
nsps["/"]?.didConnect(toNamespace: "/", payload: nil)
|
||||
}
|
||||
|
||||
for (nsp, socket) in nsps where socket.status == .connecting {
|
||||
if version.rawValue < 3 && nsp == "/" {
|
||||
continue
|
||||
}
|
||||
|
||||
connectSocket(socket, withPayload: socket.connectPayload)
|
||||
}
|
||||
}
|
||||
|
||||
/// Called when the engine receives a ping message.
|
||||
open func engineDidReceivePing() {
|
||||
handleQueue.async {
|
||||
self._engineDidReceivePing()
|
||||
}
|
||||
}
|
||||
|
||||
private func _engineDidReceivePing() {
|
||||
emitAll(clientEvent: .ping, data: [])
|
||||
}
|
||||
|
||||
/// Called when the sends a ping to the server.
|
||||
open func engineDidSendPing() {
|
||||
handleQueue.async {
|
||||
self._engineDidSendPing()
|
||||
}
|
||||
}
|
||||
|
||||
private func _engineDidSendPing() {
|
||||
emitAll(clientEvent: .ping, data: [])
|
||||
}
|
||||
|
||||
/// Called when the engine receives a pong message.
|
||||
open func engineDidReceivePong() {
|
||||
handleQueue.async {
|
||||
self._engineDidReceivePong()
|
||||
}
|
||||
}
|
||||
|
||||
private func _engineDidReceivePong() {
|
||||
emitAll(clientEvent: .pong, data: [])
|
||||
}
|
||||
|
||||
/// Called when the sends a pong to the server.
|
||||
open func engineDidSendPong() {
|
||||
handleQueue.async {
|
||||
self._engineDidSendPong()
|
||||
}
|
||||
}
|
||||
|
||||
private func _engineDidSendPong() {
|
||||
emitAll(clientEvent: .pong, data: [])
|
||||
}
|
||||
|
||||
private func forAll(do: (SocketIOClient) throws -> ()) rethrows {
|
||||
for (_, socket) in nsps {
|
||||
try `do`(socket)
|
||||
}
|
||||
}
|
||||
|
||||
/// Called when when upgrading the http connection to a websocket connection.
|
||||
///
|
||||
/// - parameter headers: The http headers.
|
||||
open func engineDidWebsocketUpgrade(headers: [String: String]) {
|
||||
handleQueue.async {
|
||||
self._engineDidWebsocketUpgrade(headers: headers)
|
||||
}
|
||||
}
|
||||
private func _engineDidWebsocketUpgrade(headers: [String: String]) {
|
||||
emitAll(clientEvent: .websocketUpgrade, data: [headers])
|
||||
}
|
||||
|
||||
/// Called when the engine has a message that must be parsed.
|
||||
///
|
||||
/// - parameter msg: The message that needs parsing.
|
||||
open func parseEngineMessage(_ msg: String) {
|
||||
handleQueue.async {
|
||||
self._parseEngineMessage(msg)
|
||||
}
|
||||
}
|
||||
|
||||
private func _parseEngineMessage(_ msg: String) {
|
||||
guard let packet = parseSocketMessage(msg) else { return }
|
||||
guard !packet.type.isBinary else {
|
||||
waitingPackets.append(packet)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
nsps[packet.nsp]?.handlePacket(packet)
|
||||
}
|
||||
|
||||
/// Called when the engine receives binary data.
|
||||
///
|
||||
/// - parameter data: The data the engine received.
|
||||
open func parseEngineBinaryData(_ data: Data) {
|
||||
handleQueue.async {
|
||||
self._parseEngineBinaryData(data)
|
||||
}
|
||||
}
|
||||
|
||||
private func _parseEngineBinaryData(_ data: Data) {
|
||||
guard let packet = parseBinaryData(data) else { return }
|
||||
|
||||
nsps[packet.nsp]?.handlePacket(packet)
|
||||
}
|
||||
|
||||
/// Tries to reconnect to the server.
|
||||
///
|
||||
/// This will cause a `SocketClientEvent.reconnect` event to be emitted, as well as
|
||||
/// `SocketClientEvent.reconnectAttempt` events.
|
||||
open func reconnect() {
|
||||
guard !reconnecting else { return }
|
||||
|
||||
engine?.disconnect(reason: "manual reconnect")
|
||||
}
|
||||
|
||||
/// Removes the socket from the manager's control. One of the disconnect methods should be called before calling this
|
||||
/// method.
|
||||
///
|
||||
/// After calling this method the socket should no longer be considered usable.
|
||||
///
|
||||
/// - parameter socket: The socket to remove.
|
||||
/// - returns: The socket removed, if it was owned by the manager.
|
||||
@discardableResult
|
||||
open func removeSocket(_ socket: SocketIOClient) -> SocketIOClient? {
|
||||
return nsps.removeValue(forKey: socket.nsp)
|
||||
}
|
||||
|
||||
private func tryReconnect(reason: String) {
|
||||
guard reconnecting else { return }
|
||||
|
||||
DefaultSocketLogger.Logger.log("Starting reconnect", type: SocketManager.logType)
|
||||
|
||||
// Set status to connecting and emit reconnect for all sockets
|
||||
forAll {socket in
|
||||
guard socket.status == .connected else { return }
|
||||
|
||||
socket.setReconnecting(reason: reason)
|
||||
}
|
||||
|
||||
_tryReconnect()
|
||||
}
|
||||
|
||||
private func _tryReconnect() {
|
||||
guard reconnects && reconnecting && status != .disconnected else { return }
|
||||
|
||||
if reconnectAttempts != -1 && currentReconnectAttempt + 1 > reconnectAttempts {
|
||||
return didDisconnect(reason: "Reconnect Failed")
|
||||
}
|
||||
|
||||
DefaultSocketLogger.Logger.log("Trying to reconnect", type: SocketManager.logType)
|
||||
|
||||
forAll {socket in
|
||||
guard socket.status == .connecting else { return }
|
||||
|
||||
socket.handleClientEvent(.reconnectAttempt, data: [(reconnectAttempts - currentReconnectAttempt)])
|
||||
}
|
||||
|
||||
currentReconnectAttempt += 1
|
||||
connect()
|
||||
|
||||
let interval = reconnectInterval(attempts: currentReconnectAttempt)
|
||||
DefaultSocketLogger.Logger.log("Scheduling reconnect in \(interval)s", type: SocketManager.logType)
|
||||
handleQueue.asyncAfter(deadline: .now() + interval, execute: _tryReconnect)
|
||||
}
|
||||
|
||||
func reconnectInterval(attempts: Int) -> Double {
|
||||
// apply exponential factor
|
||||
let backoffFactor = pow(1.5, attempts)
|
||||
let interval = Double(reconnectWait) * Double(truncating: backoffFactor as NSNumber)
|
||||
// add in a random factor smooth thundering herds
|
||||
let rand = Double.random(in: 0 ..< 1)
|
||||
let randomFactor = rand * randomizationFactor * Double(truncating: interval as NSNumber)
|
||||
// add in random factor, and clamp to min and max values
|
||||
let combined = interval + randomFactor
|
||||
return Double(fmax(Double(reconnectWait), fmin(combined, Double(reconnectWaitMax))))
|
||||
}
|
||||
|
||||
/// Sets manager specific configs.
|
||||
///
|
||||
/// parameter config: The configs that should be set.
|
||||
open func setConfigs(_ config: SocketIOClientConfiguration) {
|
||||
for option in config {
|
||||
switch option {
|
||||
case let .forceNew(new):
|
||||
forceNew = new
|
||||
case let .handleQueue(queue):
|
||||
handleQueue = queue
|
||||
case let .reconnects(reconnects):
|
||||
self.reconnects = reconnects
|
||||
case let .reconnectAttempts(attempts):
|
||||
reconnectAttempts = attempts
|
||||
case let .reconnectWait(wait):
|
||||
reconnectWait = abs(wait)
|
||||
case let .reconnectWaitMax(wait):
|
||||
reconnectWaitMax = abs(wait)
|
||||
case let .randomizationFactor(factor):
|
||||
randomizationFactor = factor
|
||||
case let .log(log):
|
||||
DefaultSocketLogger.Logger.log = log
|
||||
case let .logger(logger):
|
||||
DefaultSocketLogger.Logger = logger
|
||||
case let .version(num):
|
||||
version = num
|
||||
case _:
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
_config = config
|
||||
|
||||
if socketURL.absoluteString.hasPrefix("https://") {
|
||||
_config.insert(.secure(true))
|
||||
}
|
||||
|
||||
_config.insert(.path("/socket.io/"), replacing: false)
|
||||
|
||||
// If `ConfigSettable` & `SocketEngineSpec`, update its configs.
|
||||
if var settableEngine = engine as? ConfigSettable & SocketEngineSpec {
|
||||
settableEngine.engineQueue.sync {
|
||||
settableEngine.setConfigs(self._config)
|
||||
}
|
||||
|
||||
engine = settableEngine
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns a `SocketIOClient` for the given namespace. This socket shares a transport with the manager.
|
||||
///
|
||||
/// Calling multiple times returns the same socket.
|
||||
///
|
||||
/// Sockets created from this method are retained by the manager.
|
||||
/// Call one of the `disconnectSocket` methods on this class to remove the socket from manager control.
|
||||
/// Or call `SocketIOClient.disconnect()` on the client.
|
||||
///
|
||||
/// - parameter nsp: The namespace for the socket.
|
||||
/// - returns: A `SocketIOClient` for the given namespace.
|
||||
open func socket(forNamespace nsp: String) -> SocketIOClient {
|
||||
assert(nsp.hasPrefix("/"), "forNamespace must have a leading /")
|
||||
|
||||
if let socket = nsps[nsp] {
|
||||
return socket
|
||||
}
|
||||
|
||||
let client = SocketIOClient(manager: self, nsp: nsp)
|
||||
|
||||
nsps[nsp] = client
|
||||
|
||||
return client
|
||||
}
|
||||
|
||||
// Test properties
|
||||
|
||||
func setTestStatus(_ status: SocketIOStatus) {
|
||||
self.status = status
|
||||
}
|
||||
}
|
||||
148
Source/SocketIO/Manager/SocketManagerSpec.swift
Normal file
148
Source/SocketIO/Manager/SocketManagerSpec.swift
Normal file
@ -0,0 +1,148 @@
|
||||
//
|
||||
// Created by Erik Little on 10/18/17.
|
||||
//
|
||||
// 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.
|
||||
|
||||
import Dispatch
|
||||
import Foundation
|
||||
|
||||
// TODO Fix the types so that we aren't using concrete types
|
||||
|
||||
///
|
||||
/// A manager for a socket.io connection.
|
||||
///
|
||||
/// A `SocketManagerSpec` is responsible for multiplexing multiple namespaces through a single `SocketEngineSpec`.
|
||||
///
|
||||
/// Example with `SocketManager`:
|
||||
///
|
||||
/// ```swift
|
||||
/// let manager = SocketManager(socketURL: URL(string:"http://localhost:8080/")!)
|
||||
/// let defaultNamespaceSocket = manager.defaultSocket
|
||||
/// let swiftSocket = manager.socket(forNamespace: "/swift")
|
||||
///
|
||||
/// // defaultNamespaceSocket and swiftSocket both share a single connection to the server
|
||||
/// ```
|
||||
///
|
||||
/// Sockets created through the manager are retained by the manager. So at the very least, a single strong reference
|
||||
/// to the manager must be maintained to keep sockets alive.
|
||||
///
|
||||
/// To disconnect a socket and remove it from the manager, either call `SocketIOClient.disconnect()` on the socket,
|
||||
/// or call one of the `disconnectSocket` methods on this class.
|
||||
///
|
||||
public protocol SocketManagerSpec : SocketEngineClient {
|
||||
// MARK: Properties
|
||||
|
||||
/// Returns the socket associated with the default namespace ("/").
|
||||
var defaultSocket: SocketIOClient { get }
|
||||
|
||||
/// The engine for this manager.
|
||||
var engine: SocketEngineSpec? { get set }
|
||||
|
||||
/// If `true` then every time `connect` is called, a new engine will be created.
|
||||
var forceNew: Bool { get set }
|
||||
|
||||
// TODO Per socket queues?
|
||||
/// The queue that all interaction with the client should occur on. This is the queue that event handlers are
|
||||
/// called on.
|
||||
var handleQueue: DispatchQueue { get set }
|
||||
|
||||
/// The sockets in this manager indexed by namespace.
|
||||
var nsps: [String: SocketIOClient] { get set }
|
||||
|
||||
/// If `true`, this manager will try and reconnect on any disconnects.
|
||||
var reconnects: Bool { get set }
|
||||
|
||||
/// The minimum number of seconds to wait before attempting to reconnect.
|
||||
var reconnectWait: Int { get set }
|
||||
|
||||
/// The maximum number of seconds to wait before attempting to reconnect.
|
||||
var reconnectWaitMax: Int { get set }
|
||||
|
||||
/// The randomization factor for calculating reconnect jitter.
|
||||
var randomizationFactor: Double { get set }
|
||||
|
||||
/// The URL of the socket.io server.
|
||||
var socketURL: URL { get }
|
||||
|
||||
/// The status of this manager.
|
||||
var status: SocketIOStatus { get }
|
||||
|
||||
/// The version of socket.io in use.
|
||||
var version: SocketIOVersion { get }
|
||||
|
||||
// MARK: Methods
|
||||
|
||||
/// Connects the underlying transport.
|
||||
func connect()
|
||||
|
||||
/// Connects a socket through this manager's engine.
|
||||
///
|
||||
/// - parameter socket: The socket who we should connect through this manager.
|
||||
/// - parameter withPayload: Optional payload to send on connect
|
||||
func connectSocket(_ socket: SocketIOClient, withPayload: [String: Any]?)
|
||||
|
||||
/// Called when the manager has disconnected from socket.io.
|
||||
///
|
||||
/// - parameter reason: The reason for the disconnection.
|
||||
func didDisconnect(reason: String)
|
||||
|
||||
/// Disconnects the manager and all associated sockets.
|
||||
func disconnect()
|
||||
|
||||
/// Disconnects the given socket.
|
||||
///
|
||||
/// - parameter socket: The socket to disconnect.
|
||||
func disconnectSocket(_ socket: SocketIOClient)
|
||||
|
||||
/// Disconnects the socket associated with `forNamespace`.
|
||||
///
|
||||
/// - parameter nsp: The namespace to disconnect from.
|
||||
func disconnectSocket(forNamespace nsp: String)
|
||||
|
||||
/// Sends an event to the server on all namespaces in this manager.
|
||||
///
|
||||
/// - parameter event: The event to send.
|
||||
/// - parameter items: The data to send with this event.
|
||||
func emitAll(_ event: String, _ items: SocketData...)
|
||||
|
||||
/// Tries to reconnect to the server.
|
||||
///
|
||||
/// This will cause a `disconnect` event to be emitted, as well as an `reconnectAttempt` event.
|
||||
func reconnect()
|
||||
|
||||
/// Removes the socket from the manager's control.
|
||||
/// After calling this method the socket should no longer be considered usable.
|
||||
///
|
||||
/// - parameter socket: The socket to remove.
|
||||
/// - returns: The socket removed, if it was owned by the manager.
|
||||
@discardableResult
|
||||
func removeSocket(_ socket: SocketIOClient) -> SocketIOClient?
|
||||
|
||||
/// Returns a `SocketIOClient` for the given namespace. This socket shares a transport with the manager.
|
||||
///
|
||||
/// Calling multiple times returns the same socket.
|
||||
///
|
||||
/// Sockets created from this method are retained by the manager.
|
||||
/// Call one of the `disconnectSocket` methods on the implementing class to remove the socket from manager control.
|
||||
/// Or call `SocketIOClient.disconnect()` on the client.
|
||||
///
|
||||
/// - parameter nsp: The namespace for the socket.
|
||||
/// - returns: A `SocketIOClient` for the given namespace.
|
||||
func socket(forNamespace nsp: String) -> SocketIOClient
|
||||
}
|
||||
250
Source/SocketIO/Parse/SocketPacket.swift
Normal file
250
Source/SocketIO/Parse/SocketPacket.swift
Normal file
@ -0,0 +1,250 @@
|
||||
//
|
||||
// SocketPacket.swift
|
||||
// Socket.IO-Client-Swift
|
||||
//
|
||||
// Created by Erik Little on 1/18/15.
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
/// A struct that represents a socket.io packet.
|
||||
public struct SocketPacket : CustomStringConvertible {
|
||||
// MARK: Properties
|
||||
|
||||
private static let logType = "SocketPacket"
|
||||
|
||||
/// The namespace for this packet.
|
||||
public let nsp: String
|
||||
|
||||
/// If > 0 then this packet is using acking.
|
||||
public let id: Int
|
||||
|
||||
/// The type of this packet.
|
||||
public let type: PacketType
|
||||
|
||||
/// An array of binary data for this packet.
|
||||
public internal(set) var binary: [Data]
|
||||
|
||||
/// The data for this event.
|
||||
///
|
||||
/// Note: This includes all data inside of the socket.io packet payload array, which includes the event name for
|
||||
/// event type packets.
|
||||
public internal(set) var data: [Any]
|
||||
|
||||
/// Returns the payload for this packet, minus the event name if this is an event or binaryEvent type packet.
|
||||
public var args: [Any] {
|
||||
if type == .event || type == .binaryEvent && data.count != 0 {
|
||||
return Array(data.dropFirst())
|
||||
} else {
|
||||
return data
|
||||
}
|
||||
}
|
||||
|
||||
private let placeholders: Int
|
||||
|
||||
/// A string representation of this packet.
|
||||
public var description: String {
|
||||
return "SocketPacket {type: \(String(type.rawValue)); data: " +
|
||||
"\(String(describing: data)); id: \(id); placeholders: \(placeholders); nsp: \(nsp)}"
|
||||
}
|
||||
|
||||
/// The event name for this packet.
|
||||
public var event: String {
|
||||
return String(describing: data[0])
|
||||
}
|
||||
|
||||
/// A string representation of this packet.
|
||||
public var packetString: String {
|
||||
return createPacketString()
|
||||
}
|
||||
|
||||
init(type: PacketType, data: [Any] = [Any](), id: Int = -1, nsp: String, placeholders: Int = 0,
|
||||
binary: [Data] = [Data]()) {
|
||||
self.data = data
|
||||
self.id = id
|
||||
self.nsp = nsp
|
||||
self.type = type
|
||||
self.placeholders = placeholders
|
||||
self.binary = binary
|
||||
}
|
||||
|
||||
mutating func addData(_ data: Data) -> Bool {
|
||||
if placeholders == binary.count {
|
||||
return true
|
||||
}
|
||||
|
||||
binary.append(data)
|
||||
|
||||
if placeholders == binary.count {
|
||||
fillInPlaceholders()
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
private func completeMessage(_ message: String) -> String {
|
||||
guard data.count != 0 else { return message + "[]" }
|
||||
guard let jsonSend = try? data.toJSON(), let jsonString = String(data: jsonSend, encoding: .utf8) else {
|
||||
DefaultSocketLogger.Logger.error("Error creating JSON object in SocketPacket.completeMessage",
|
||||
type: SocketPacket.logType)
|
||||
|
||||
return message + "[]"
|
||||
}
|
||||
|
||||
return message + jsonString
|
||||
}
|
||||
|
||||
private func createPacketString() -> String {
|
||||
let typeString = String(type.rawValue)
|
||||
// Binary count?
|
||||
let binaryCountString = typeString + (type.isBinary ? "\(String(binary.count))-" : "")
|
||||
// Namespace?
|
||||
let nspString = binaryCountString + (nsp != "/" ? "\(nsp)," : "")
|
||||
// Ack number?
|
||||
let idString = nspString + (id != -1 ? String(id) : "")
|
||||
|
||||
return completeMessage(idString)
|
||||
}
|
||||
|
||||
// Called when we have all the binary data for a packet
|
||||
// calls _fillInPlaceholders, which replaces placeholders with the
|
||||
// corresponding binary
|
||||
private mutating func fillInPlaceholders() {
|
||||
data = data.map(_fillInPlaceholders)
|
||||
}
|
||||
|
||||
// Helper method that looks for placeholders
|
||||
// If object is a collection it will recurse
|
||||
// Returns the object if it is not a placeholder or the corresponding
|
||||
// binary data
|
||||
private func _fillInPlaceholders(_ object: Any) -> Any {
|
||||
switch object {
|
||||
case let dict as JSON:
|
||||
if dict["_placeholder"] as? Bool ?? false {
|
||||
return binary[dict["num"] as! Int]
|
||||
} else {
|
||||
return dict.reduce(into: JSON(), {cur, keyValue in
|
||||
cur[keyValue.0] = _fillInPlaceholders(keyValue.1)
|
||||
})
|
||||
}
|
||||
case let arr as [Any]:
|
||||
return arr.map(_fillInPlaceholders)
|
||||
default:
|
||||
return object
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public extension SocketPacket {
|
||||
// MARK: PacketType enum
|
||||
|
||||
/// The type of packets.
|
||||
enum PacketType: Int {
|
||||
// MARK: Cases
|
||||
|
||||
/// Connect: 0
|
||||
case connect
|
||||
|
||||
/// Disconnect: 1
|
||||
case disconnect
|
||||
|
||||
/// Event: 2
|
||||
case event
|
||||
|
||||
/// Ack: 3
|
||||
case ack
|
||||
|
||||
/// Error: 4
|
||||
case error
|
||||
|
||||
/// Binary Event: 5
|
||||
case binaryEvent
|
||||
|
||||
/// Binary Ack: 6
|
||||
case binaryAck
|
||||
|
||||
// MARK: Properties
|
||||
|
||||
/// Whether or not this type is binary
|
||||
public var isBinary: Bool {
|
||||
return self == .binaryAck || self == .binaryEvent
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension SocketPacket {
|
||||
private static func findType(_ binCount: Int, ack: Bool) -> PacketType {
|
||||
switch binCount {
|
||||
case 0 where !ack:
|
||||
return .event
|
||||
case 0 where ack:
|
||||
return .ack
|
||||
case _ where !ack:
|
||||
return .binaryEvent
|
||||
case _ where ack:
|
||||
return .binaryAck
|
||||
default:
|
||||
return .error
|
||||
}
|
||||
}
|
||||
|
||||
static func packetFromEmit(_ items: [Any], id: Int, nsp: String, ack: Bool, checkForBinary: Bool = true) -> SocketPacket {
|
||||
if checkForBinary {
|
||||
let (parsedData, binary) = deconstructData(items)
|
||||
|
||||
return SocketPacket(type: findType(binary.count, ack: ack), data: parsedData, id: id, nsp: nsp,
|
||||
binary: binary)
|
||||
} else {
|
||||
return SocketPacket(type: findType(0, ack: ack), data: items, id: id, nsp: nsp)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private extension SocketPacket {
|
||||
// Recursive function that looks for NSData in collections
|
||||
static func shred(_ data: Any, binary: inout [Data]) -> Any {
|
||||
let placeholder = ["_placeholder": true, "num": binary.count] as JSON
|
||||
|
||||
switch data {
|
||||
case let bin as Data:
|
||||
binary.append(bin)
|
||||
|
||||
return placeholder
|
||||
case let arr as [Any]:
|
||||
return arr.map({shred($0, binary: &binary)})
|
||||
case let dict as JSON:
|
||||
return dict.reduce(into: JSON(), {cur, keyValue in
|
||||
cur[keyValue.0] = shred(keyValue.1, binary: &binary)
|
||||
})
|
||||
default:
|
||||
return data
|
||||
}
|
||||
}
|
||||
|
||||
// Removes binary data from emit data
|
||||
// Returns a type containing the de-binaryed data and the binary
|
||||
static func deconstructData(_ data: [Any]) -> ([Any], [Data]) {
|
||||
var binary = [Data]()
|
||||
|
||||
return (data.map({ shred($0, binary: &binary) }), binary)
|
||||
}
|
||||
}
|
||||
181
Source/SocketIO/Parse/SocketParsable.swift
Normal file
181
Source/SocketIO/Parse/SocketParsable.swift
Normal file
@ -0,0 +1,181 @@
|
||||
//
|
||||
// SocketParsable.swift
|
||||
// Socket.IO-Client-Swift
|
||||
//
|
||||
// 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.
|
||||
|
||||
import Foundation
|
||||
|
||||
/// Defines that a type will be able to parse socket.io-protocol messages.
|
||||
public protocol SocketParsable : AnyObject {
|
||||
// MARK: Methods
|
||||
|
||||
/// Called when the engine has received some binary data that should be attached to a packet.
|
||||
///
|
||||
/// Packets binary data should be sent directly after the packet that expects it, so there's confusion over
|
||||
/// where the data should go. Data should be received in the order it is sent, so that the correct data is put
|
||||
/// into the correct placeholder.
|
||||
///
|
||||
/// - parameter data: The data that should be attached to a packet.
|
||||
func parseBinaryData(_ data: Data) -> SocketPacket?
|
||||
|
||||
/// Called when the engine has received a string that should be parsed into a socket.io packet.
|
||||
///
|
||||
/// - parameter message: The string that needs parsing.
|
||||
/// - returns: A completed socket packet if there is no more data left to collect.
|
||||
func parseSocketMessage(_ message: String) -> SocketPacket?
|
||||
}
|
||||
|
||||
/// Errors that can be thrown during parsing.
|
||||
public enum SocketParsableError : Error {
|
||||
// MARK: Cases
|
||||
|
||||
/// Thrown when a packet received has an invalid data array, or is missing the data array.
|
||||
case invalidDataArray
|
||||
|
||||
/// Thrown when an malformed packet is received.
|
||||
case invalidPacket
|
||||
|
||||
/// Thrown when the parser receives an unknown packet type.
|
||||
case invalidPacketType
|
||||
}
|
||||
|
||||
/// Says that a type will be able to buffer binary data before all data for an event has come in.
|
||||
public protocol SocketDataBufferable : AnyObject {
|
||||
// MARK: Properties
|
||||
|
||||
/// A list of packets that are waiting for binary data.
|
||||
///
|
||||
/// The way that socket.io works all data should be sent directly after each packet.
|
||||
/// So this should ideally be an array of one packet waiting for data.
|
||||
///
|
||||
/// **This should not be modified directly.**
|
||||
var waitingPackets: [SocketPacket] { get set }
|
||||
}
|
||||
|
||||
public extension SocketParsable where Self: SocketManagerSpec & SocketDataBufferable {
|
||||
/// Parses a message from the engine, returning a complete SocketPacket or throwing.
|
||||
///
|
||||
/// - parameter message: The message to parse.
|
||||
/// - returns: A completed packet, or throwing.
|
||||
internal func parseString(_ message: String) throws -> SocketPacket {
|
||||
var reader = SocketStringReader(message: message)
|
||||
|
||||
guard let type = Int(reader.read(count: 1)).flatMap({ SocketPacket.PacketType(rawValue: $0) }) else {
|
||||
throw SocketParsableError.invalidPacketType
|
||||
}
|
||||
|
||||
if !reader.hasNext {
|
||||
return SocketPacket(type: type, nsp: "/")
|
||||
}
|
||||
|
||||
var namespace = "/"
|
||||
var placeholders = -1
|
||||
|
||||
if type.isBinary {
|
||||
if let holders = Int(reader.readUntilOccurence(of: "-")) {
|
||||
placeholders = holders
|
||||
} else {
|
||||
throw SocketParsableError.invalidPacket
|
||||
}
|
||||
}
|
||||
|
||||
if reader.currentCharacter == "/" {
|
||||
namespace = reader.readUntilOccurence(of: ",")
|
||||
}
|
||||
|
||||
if !reader.hasNext {
|
||||
return SocketPacket(type: type, nsp: namespace, placeholders: placeholders)
|
||||
}
|
||||
|
||||
var idString = ""
|
||||
|
||||
if type == .error {
|
||||
reader.advance(by: -1)
|
||||
} else {
|
||||
while let int = Int(reader.read(count: 1)) {
|
||||
idString += String(int)
|
||||
}
|
||||
|
||||
reader.advance(by: -2)
|
||||
}
|
||||
|
||||
var dataArray = String(message.utf16[message.utf16.index(reader.currentIndex, offsetBy: 1)...])!
|
||||
|
||||
if (type == .error || type == .connect) && !dataArray.hasPrefix("[") && !dataArray.hasSuffix("]") {
|
||||
dataArray = "[" + dataArray + "]"
|
||||
}
|
||||
|
||||
let data = try parseData(dataArray)
|
||||
|
||||
return SocketPacket(type: type, data: data, id: Int(idString) ?? -1, nsp: namespace, placeholders: placeholders)
|
||||
}
|
||||
|
||||
// Parses data for events
|
||||
private func parseData(_ data: String) throws -> [Any] {
|
||||
do {
|
||||
return try data.toArray()
|
||||
} catch {
|
||||
throw SocketParsableError.invalidDataArray
|
||||
}
|
||||
}
|
||||
|
||||
/// Called when the engine has received a string that should be parsed into a socket.io packet.
|
||||
///
|
||||
/// - parameter message: The string that needs parsing.
|
||||
/// - returns: A completed socket packet or nil if the packet is invalid.
|
||||
func parseSocketMessage(_ message: String) -> SocketPacket? {
|
||||
guard !message.isEmpty else { return nil }
|
||||
|
||||
DefaultSocketLogger.Logger.log("Parsing \(message)", type: "SocketParser")
|
||||
|
||||
do {
|
||||
let packet = try parseString(message)
|
||||
|
||||
DefaultSocketLogger.Logger.log("Decoded packet as: \(packet.description)", type: "SocketParser")
|
||||
|
||||
return packet
|
||||
} catch {
|
||||
DefaultSocketLogger.Logger.error("\(error): \(message)", type: "SocketParser")
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
/// Called when the engine has received some binary data that should be attached to a packet.
|
||||
///
|
||||
/// Packets binary data should be sent directly after the packet that expects it, so there's confusion over
|
||||
/// where the data should go. Data should be received in the order it is sent, so that the correct data is put
|
||||
/// into the correct placeholder.
|
||||
///
|
||||
/// - parameter data: The data that should be attached to a packet.
|
||||
/// - returns: A completed socket packet if there is no more data left to collect.
|
||||
func parseBinaryData(_ data: Data) -> SocketPacket? {
|
||||
guard !waitingPackets.isEmpty else {
|
||||
DefaultSocketLogger.Logger.error("Got data when not remaking packet", type: "SocketParser")
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Should execute event?
|
||||
guard waitingPackets[waitingPackets.count - 1].addData(data) else { return nil }
|
||||
|
||||
return waitingPackets.removeLast()
|
||||
}
|
||||
}
|
||||
132
Source/SocketIO/Util/SocketExtensions.swift
Normal file
132
Source/SocketIO/Util/SocketExtensions.swift
Normal file
@ -0,0 +1,132 @@
|
||||
//
|
||||
// SocketExtensions.swift
|
||||
// Socket.IO-Client-Swift
|
||||
//
|
||||
// Created by Erik Little on 7/1/2016.
|
||||
//
|
||||
// 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.
|
||||
|
||||
import Foundation
|
||||
import Starscream
|
||||
|
||||
enum JSONError : Error {
|
||||
case notArray
|
||||
case notNSDictionary
|
||||
}
|
||||
|
||||
extension Array {
|
||||
func toJSON() throws -> Data {
|
||||
return try JSONSerialization.data(withJSONObject: self, options: JSONSerialization.WritingOptions(rawValue: 0))
|
||||
}
|
||||
}
|
||||
|
||||
extension CharacterSet {
|
||||
static var allowedURLCharacterSet: CharacterSet {
|
||||
return CharacterSet(charactersIn: "!*'();:@&=+$,/?%#[]\" {}^|").inverted
|
||||
}
|
||||
}
|
||||
|
||||
extension Dictionary where Key == String, Value == Any {
|
||||
private static func keyValueToSocketIOClientOption(key: String, value: Any) -> SocketIOClientOption? {
|
||||
switch (key, value) {
|
||||
case let ("connectParams", params as [String: Any]):
|
||||
return .connectParams(params)
|
||||
case let ("cookies", cookies as [HTTPCookie]):
|
||||
return .cookies(cookies)
|
||||
case let ("extraHeaders", headers as [String: String]):
|
||||
return .extraHeaders(headers)
|
||||
case let ("forceNew", force as Bool):
|
||||
return .forceNew(force)
|
||||
case let ("forcePolling", force as Bool):
|
||||
return .forcePolling(force)
|
||||
case let ("forceWebsockets", force as Bool):
|
||||
return .forceWebsockets(force)
|
||||
case let ("handleQueue", queue as DispatchQueue):
|
||||
return .handleQueue(queue)
|
||||
case let ("log", log as Bool):
|
||||
return .log(log)
|
||||
case let ("logger", logger as SocketLogger):
|
||||
return .logger(logger)
|
||||
case let ("path", path as String):
|
||||
return .path(path)
|
||||
case let ("reconnects", reconnects as Bool):
|
||||
return .reconnects(reconnects)
|
||||
case let ("reconnectAttempts", attempts as Int):
|
||||
return .reconnectAttempts(attempts)
|
||||
case let ("reconnectWait", wait as Int):
|
||||
return .reconnectWait(wait)
|
||||
case let ("reconnectWaitMax", wait as Int):
|
||||
return .reconnectWaitMax(wait)
|
||||
case let ("randomizationFactor", factor as Double):
|
||||
return .randomizationFactor(factor)
|
||||
case let ("secure", secure as Bool):
|
||||
return .secure(secure)
|
||||
case let ("security", security as CertificatePinning):
|
||||
return .security(security)
|
||||
case let ("selfSigned", selfSigned as Bool):
|
||||
return .selfSigned(selfSigned)
|
||||
case let ("sessionDelegate", delegate as URLSessionDelegate):
|
||||
return .sessionDelegate(delegate)
|
||||
case let ("compress", compress as Bool):
|
||||
return compress ? .compress : nil
|
||||
case let ("enableSOCKSProxy", enable as Bool):
|
||||
return .enableSOCKSProxy(enable)
|
||||
case let ("version", version as Int):
|
||||
return .version(SocketIOVersion(rawValue: version) ?? .three)
|
||||
case _:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func toSocketConfiguration() -> SocketIOClientConfiguration {
|
||||
var options = [] as SocketIOClientConfiguration
|
||||
|
||||
for (rawKey, value) in self {
|
||||
if let opt = Dictionary.keyValueToSocketIOClientOption(key: rawKey, value: value) {
|
||||
options.insert(opt)
|
||||
}
|
||||
}
|
||||
|
||||
return options
|
||||
}
|
||||
}
|
||||
|
||||
extension String {
|
||||
func toArray() throws -> [Any] {
|
||||
guard let stringData = data(using: .utf16, allowLossyConversion: false) else { return [] }
|
||||
guard let array = try JSONSerialization.jsonObject(with: stringData, options: .mutableContainers) as? [Any] else {
|
||||
throw JSONError.notArray
|
||||
}
|
||||
|
||||
return array
|
||||
}
|
||||
|
||||
func toDictionary() throws -> [String: Any] {
|
||||
guard let binData = data(using: .utf16, allowLossyConversion: false) else { return [:] }
|
||||
guard let json = try JSONSerialization.jsonObject(with: binData, options: .allowFragments) as? [String: Any] else {
|
||||
throw JSONError.notNSDictionary
|
||||
}
|
||||
|
||||
return json
|
||||
}
|
||||
|
||||
func urlEncode() -> String? {
|
||||
return addingPercentEncoding(withAllowedCharacters: .allowedURLCharacterSet)
|
||||
}
|
||||
}
|
||||
@ -24,33 +24,47 @@
|
||||
|
||||
import Foundation
|
||||
|
||||
public protocol SocketLogger : class {
|
||||
/// Represents a class will log client events.
|
||||
public protocol SocketLogger : AnyObject {
|
||||
// MARK: Properties
|
||||
|
||||
/// Whether to log or not
|
||||
var log: Bool { get set }
|
||||
|
||||
|
||||
// MARK: Methods
|
||||
|
||||
/// Normal log messages
|
||||
func log(message: String, type: String, args: AnyObject...)
|
||||
|
||||
///
|
||||
/// - parameter message: The message being logged. Can include `%@` that will be replaced with `args`
|
||||
/// - parameter type: The type of entity that called for logging.
|
||||
/// - parameter args: Any args that should be inserted into the message. May be left out.
|
||||
func log(_ message: @autoclosure () -> String, type: String)
|
||||
|
||||
/// Error Messages
|
||||
func error(message: String, type: String, args: AnyObject...)
|
||||
///
|
||||
/// - parameter message: The message being logged. Can include `%@` that will be replaced with `args`
|
||||
/// - parameter type: The type of entity that called for logging.
|
||||
/// - parameter args: Any args that should be inserted into the message. May be left out.
|
||||
func error(_ message: @autoclosure () -> String, type: String)
|
||||
}
|
||||
|
||||
public extension SocketLogger {
|
||||
func log(message: String, type: String, args: AnyObject...) {
|
||||
abstractLog("LOG", message: message, type: type, args: args)
|
||||
}
|
||||
|
||||
func error(message: String, type: String, args: AnyObject...) {
|
||||
abstractLog("ERROR", message: message, type: type, args: args)
|
||||
}
|
||||
|
||||
private func abstractLog(logType: String, message: String, type: String, args: [AnyObject]) {
|
||||
/// Default implementation.
|
||||
func log(_ message: @autoclosure () -> String, type: String) {
|
||||
guard log else { return }
|
||||
|
||||
let newArgs = args.map({arg -> CVarArgType in String(arg)})
|
||||
let replaced = String(format: message, arguments: newArgs)
|
||||
|
||||
NSLog("%@ %@: %@", logType, type, replaced)
|
||||
|
||||
abstractLog("LOG", message: message(), type: type)
|
||||
}
|
||||
|
||||
/// Default implementation.
|
||||
func error(_ message: @autoclosure () -> String, type: String) {
|
||||
guard log else { return }
|
||||
|
||||
abstractLog("ERROR", message: message(), type: type)
|
||||
}
|
||||
|
||||
private func abstractLog(_ logType: String, message: @autoclosure () -> String, type: String) {
|
||||
NSLog("\(logType) \(type): %@", message())
|
||||
}
|
||||
}
|
||||
|
||||
@ -24,45 +24,50 @@
|
||||
|
||||
struct SocketStringReader {
|
||||
let message: String
|
||||
var currentIndex: String.Index
|
||||
var currentIndex: String.UTF16View.Index
|
||||
var hasNext: Bool {
|
||||
return currentIndex != message.endIndex
|
||||
return currentIndex != message.utf16.endIndex
|
||||
}
|
||||
|
||||
|
||||
var currentCharacter: String {
|
||||
return String(message[currentIndex])
|
||||
return String(UnicodeScalar(message.utf16[currentIndex])!)
|
||||
}
|
||||
|
||||
|
||||
init(message: String) {
|
||||
self.message = message
|
||||
currentIndex = message.startIndex
|
||||
currentIndex = message.utf16.startIndex
|
||||
}
|
||||
|
||||
mutating func advanceIndexBy(n: Int) {
|
||||
currentIndex = currentIndex.advancedBy(n)
|
||||
|
||||
@discardableResult
|
||||
mutating func advance(by: Int) -> String.UTF16View.Index {
|
||||
currentIndex = message.utf16.index(currentIndex, offsetBy: by)
|
||||
|
||||
return currentIndex
|
||||
}
|
||||
|
||||
mutating func read(readLength: Int) -> String {
|
||||
let readString = message[currentIndex..<currentIndex.advancedBy(readLength)]
|
||||
advanceIndexBy(readLength)
|
||||
|
||||
|
||||
mutating func read(count: Int) -> String {
|
||||
let readString = String(message.utf16[currentIndex..<message.utf16.index(currentIndex, offsetBy: count)])!
|
||||
|
||||
advance(by: count)
|
||||
|
||||
return readString
|
||||
}
|
||||
|
||||
mutating func readUntilStringOccurence(string: String) -> String {
|
||||
let substring = message[currentIndex..<message.endIndex]
|
||||
guard let foundRange = substring.rangeOfString(string) else {
|
||||
currentIndex = message.endIndex
|
||||
|
||||
return substring
|
||||
|
||||
mutating func readUntilOccurence(of string: String) -> String {
|
||||
let substring = message.utf16[currentIndex...]
|
||||
|
||||
guard let foundIndex = substring.firstIndex(where: { $0 == string.utf16.first! }) else {
|
||||
currentIndex = message.utf16.endIndex
|
||||
|
||||
return String(substring)!
|
||||
}
|
||||
|
||||
advanceIndexBy(message.startIndex.distanceTo(foundRange.startIndex) + 1)
|
||||
|
||||
return substring.substringToIndex(foundRange.startIndex)
|
||||
|
||||
advance(by: substring.distance(from: substring.startIndex, to: foundIndex) + 1)
|
||||
|
||||
return String(substring[substring.startIndex..<foundIndex])!
|
||||
}
|
||||
|
||||
|
||||
mutating func readUntilEnd() -> String {
|
||||
return read(currentIndex.distanceTo(message.endIndex))
|
||||
return read(count: message.utf16.distance(from: currentIndex, to: message.utf16.endIndex))
|
||||
}
|
||||
}
|
||||
86
Source/SocketIO/Util/SocketTypes.swift
Normal file
86
Source/SocketIO/Util/SocketTypes.swift
Normal file
@ -0,0 +1,86 @@
|
||||
//
|
||||
// SocketTypes.swift
|
||||
// Socket.IO-Client-Swift
|
||||
//
|
||||
// Created by Erik Little on 4/8/15.
|
||||
//
|
||||
// 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.
|
||||
|
||||
import Foundation
|
||||
|
||||
/// A marking protocol that says a type can be represented in a socket.io packet.
|
||||
///
|
||||
/// Example:
|
||||
///
|
||||
/// ```swift
|
||||
/// struct CustomData : SocketData {
|
||||
/// let name: String
|
||||
/// let age: Int
|
||||
///
|
||||
/// func socketRepresentation() -> SocketData {
|
||||
/// return ["name": name, "age": age]
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// socket.emit("myEvent", CustomData(name: "Erik", age: 24))
|
||||
/// ```
|
||||
public protocol SocketData {
|
||||
// MARK: Methods
|
||||
|
||||
/// A representation of self that can sent over socket.io.
|
||||
func socketRepresentation() throws -> SocketData
|
||||
}
|
||||
|
||||
public extension SocketData {
|
||||
/// Default implementation. Only works for native Swift types and a few Foundation types.
|
||||
func socketRepresentation() -> SocketData {
|
||||
return self
|
||||
}
|
||||
}
|
||||
|
||||
extension Array : SocketData { }
|
||||
extension Bool : SocketData { }
|
||||
extension Dictionary : SocketData { }
|
||||
extension Double : SocketData { }
|
||||
extension Int : SocketData { }
|
||||
extension NSArray : SocketData { }
|
||||
extension Data : SocketData { }
|
||||
extension NSData : SocketData { }
|
||||
extension NSDictionary : SocketData { }
|
||||
extension NSString : SocketData { }
|
||||
extension NSNull : SocketData { }
|
||||
extension String : SocketData { }
|
||||
|
||||
/// A typealias for an ack callback.
|
||||
public typealias AckCallback = ([Any]) -> ()
|
||||
|
||||
/// A typealias for a normal callback.
|
||||
public typealias NormalCallback = ([Any], SocketAckEmitter) -> ()
|
||||
|
||||
/// A typealias for a queued POST
|
||||
public typealias Post = (msg: String, completion: (() -> ())?)
|
||||
|
||||
typealias JSON = [String: Any]
|
||||
typealias Probe = (msg: String, type: SocketEnginePacketType, data: [Data], completion: (() -> ())?)
|
||||
typealias ProbeWaitQueue = [Probe]
|
||||
|
||||
enum Either<E, V> {
|
||||
case left(E)
|
||||
case right(V)
|
||||
}
|
||||
@ -1,457 +0,0 @@
|
||||
//
|
||||
// SocketIOClient.swift
|
||||
// Socket.IO-Client-Swift
|
||||
//
|
||||
// Created by Erik Little on 11/23/14.
|
||||
//
|
||||
// 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.
|
||||
|
||||
import Foundation
|
||||
|
||||
public final class SocketIOClient : NSObject, SocketEngineClient, SocketParsable {
|
||||
public let socketURL: NSURL
|
||||
|
||||
public private(set) var engine: SocketEngineSpec?
|
||||
public private(set) var status = SocketIOClientStatus.NotConnected {
|
||||
didSet {
|
||||
switch status {
|
||||
case .Connected:
|
||||
reconnecting = false
|
||||
currentReconnectAttempt = 0
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public var forceNew = false
|
||||
public var nsp = "/"
|
||||
public var options: Set<SocketIOClientOption>
|
||||
public var reconnects = true
|
||||
public var reconnectWait = 10
|
||||
public var sid: String? {
|
||||
return nsp + "#" + (engine?.sid ?? "")
|
||||
}
|
||||
|
||||
private let emitQueue = dispatch_queue_create("com.socketio.emitQueue", DISPATCH_QUEUE_SERIAL)
|
||||
private let logType = "SocketIOClient"
|
||||
private let parseQueue = dispatch_queue_create("com.socketio.parseQueue", DISPATCH_QUEUE_SERIAL)
|
||||
|
||||
private var anyHandler: ((SocketAnyEvent) -> Void)?
|
||||
private var currentReconnectAttempt = 0
|
||||
private var handlers = [SocketEventHandler]()
|
||||
private var ackHandlers = SocketAckManager()
|
||||
private var reconnecting = false
|
||||
|
||||
private(set) var currentAck = -1
|
||||
private(set) var handleQueue = dispatch_get_main_queue()
|
||||
private(set) var reconnectAttempts = -1
|
||||
|
||||
var waitingPackets = [SocketPacket]()
|
||||
|
||||
/// Type safe way to create a new SocketIOClient. opts can be omitted
|
||||
public init(socketURL: NSURL, options: Set<SocketIOClientOption> = []) {
|
||||
self.options = options
|
||||
self.socketURL = socketURL
|
||||
|
||||
if socketURL.absoluteString.hasPrefix("https://") {
|
||||
self.options.insertIgnore(.Secure(true))
|
||||
}
|
||||
|
||||
for option in options {
|
||||
switch option {
|
||||
case let .Reconnects(reconnects):
|
||||
self.reconnects = reconnects
|
||||
case let .ReconnectAttempts(attempts):
|
||||
reconnectAttempts = attempts
|
||||
case let .ReconnectWait(wait):
|
||||
reconnectWait = abs(wait)
|
||||
case let .Nsp(nsp):
|
||||
self.nsp = nsp
|
||||
case let .Log(log):
|
||||
DefaultSocketLogger.Logger.log = log
|
||||
case let .Logger(logger):
|
||||
DefaultSocketLogger.Logger = logger
|
||||
case let .HandleQueue(queue):
|
||||
handleQueue = queue
|
||||
case let .ForceNew(force):
|
||||
forceNew = force
|
||||
default:
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
self.options.insertIgnore(.Path("/socket.io/"))
|
||||
|
||||
super.init()
|
||||
}
|
||||
|
||||
/// Not so type safe way to create a SocketIOClient, meant for Objective-C compatiblity.
|
||||
/// If using Swift it's recommended to use `init(socketURL: NSURL, options: Set<SocketIOClientOption>)`
|
||||
public convenience init(socketURL: NSURL, options: NSDictionary?) {
|
||||
self.init(socketURL: socketURL, options: options?.toSocketOptionsSet() ?? [])
|
||||
}
|
||||
|
||||
deinit {
|
||||
DefaultSocketLogger.Logger.log("Client is being released", type: logType)
|
||||
engine?.disconnect("Client Deinit")
|
||||
}
|
||||
|
||||
private func addEngine() -> SocketEngineSpec {
|
||||
DefaultSocketLogger.Logger.log("Adding engine", type: logType)
|
||||
|
||||
engine = SocketEngine(client: self, url: socketURL, options: options)
|
||||
|
||||
return engine!
|
||||
}
|
||||
|
||||
/// Connect to the server.
|
||||
public func connect() {
|
||||
connect(timeoutAfter: 0, withTimeoutHandler: nil)
|
||||
}
|
||||
|
||||
/// Connect to the server. If we aren't connected after timeoutAfter, call handler
|
||||
public func connect(timeoutAfter timeoutAfter: Int, withTimeoutHandler handler: (() -> Void)?) {
|
||||
assert(timeoutAfter >= 0, "Invalid timeout: \(timeoutAfter)")
|
||||
|
||||
guard status != .Connected else {
|
||||
DefaultSocketLogger.Logger.log("Tried connecting on an already connected socket", type: logType)
|
||||
return
|
||||
}
|
||||
|
||||
status = .Connecting
|
||||
|
||||
if engine == nil || forceNew {
|
||||
addEngine().connect()
|
||||
} else {
|
||||
engine?.connect()
|
||||
}
|
||||
|
||||
guard timeoutAfter != 0 else { return }
|
||||
|
||||
let time = dispatch_time(DISPATCH_TIME_NOW, Int64(timeoutAfter) * Int64(NSEC_PER_SEC))
|
||||
|
||||
dispatch_after(time, handleQueue) {[weak self] in
|
||||
if let this = self where this.status != .Connected && this.status != .Disconnected {
|
||||
this.status = .Disconnected
|
||||
this.engine?.disconnect("Connect timeout")
|
||||
|
||||
handler?()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func createOnAck(items: [AnyObject]) -> OnAckCallback {
|
||||
currentAck += 1
|
||||
|
||||
return {[weak self, ack = currentAck] timeout, callback in
|
||||
if let this = self {
|
||||
this.ackHandlers.addAck(ack, callback: callback)
|
||||
this._emit(items, ack: ack)
|
||||
|
||||
if timeout != 0 {
|
||||
let time = dispatch_time(DISPATCH_TIME_NOW, Int64(timeout * NSEC_PER_SEC))
|
||||
|
||||
dispatch_after(time, this.handleQueue) {
|
||||
this.ackHandlers.timeoutAck(ack)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func didConnect() {
|
||||
DefaultSocketLogger.Logger.log("Socket connected", type: logType)
|
||||
status = .Connected
|
||||
|
||||
// Don't handle as internal because something crazy could happen where
|
||||
// we disconnect before it's handled
|
||||
handleEvent("connect", data: [], isInternalMessage: false)
|
||||
}
|
||||
|
||||
func didDisconnect(reason: String) {
|
||||
guard status != .Disconnected else { return }
|
||||
|
||||
DefaultSocketLogger.Logger.log("Disconnected: %@", type: logType, args: reason)
|
||||
|
||||
status = .Disconnected
|
||||
reconnects = false
|
||||
|
||||
// Make sure the engine is actually dead.
|
||||
engine?.disconnect(reason)
|
||||
handleEvent("disconnect", data: [reason], isInternalMessage: true)
|
||||
}
|
||||
|
||||
/// Disconnects the socket. Only reconnect the same socket if you know what you're doing.
|
||||
/// Will turn off automatic reconnects.
|
||||
public func disconnect() {
|
||||
assert(status != .NotConnected, "Tried closing a NotConnected client")
|
||||
|
||||
DefaultSocketLogger.Logger.log("Closing socket", type: logType)
|
||||
|
||||
reconnects = false
|
||||
didDisconnect("Disconnect")
|
||||
}
|
||||
|
||||
/// Send a message to the server
|
||||
public func emit(event: String, _ items: AnyObject...) {
|
||||
emit(event, withItems: items)
|
||||
}
|
||||
|
||||
/// Same as emit, but meant for Objective-C
|
||||
public func emit(event: String, withItems items: [AnyObject]) {
|
||||
guard status == .Connected else {
|
||||
handleEvent("error", data: ["Tried emitting \(event) when not connected"], isInternalMessage: true)
|
||||
return
|
||||
}
|
||||
|
||||
_emit([event] + items)
|
||||
}
|
||||
|
||||
/// Sends a message to the server, requesting an ack. Use the onAck method of SocketAckHandler to add
|
||||
/// an ack.
|
||||
public func emitWithAck(event: String, _ items: AnyObject...) -> OnAckCallback {
|
||||
return emitWithAck(event, withItems: items)
|
||||
}
|
||||
|
||||
/// Same as emitWithAck, but for Objective-C
|
||||
public func emitWithAck(event: String, withItems items: [AnyObject]) -> OnAckCallback {
|
||||
return createOnAck([event] + items)
|
||||
}
|
||||
|
||||
private func _emit(data: [AnyObject], ack: Int? = nil) {
|
||||
dispatch_async(emitQueue) {
|
||||
guard self.status == .Connected else {
|
||||
self.handleEvent("error", data: ["Tried emitting when not connected"], isInternalMessage: true)
|
||||
return
|
||||
}
|
||||
|
||||
let packet = SocketPacket.packetFromEmit(data, id: ack ?? -1, nsp: self.nsp, ack: false)
|
||||
let str = packet.packetString
|
||||
|
||||
DefaultSocketLogger.Logger.log("Emitting: %@", type: self.logType, args: str)
|
||||
|
||||
self.engine?.send(str, withData: packet.binary)
|
||||
}
|
||||
}
|
||||
|
||||
// If the server wants to know that the client received data
|
||||
func emitAck(ack: Int, withItems items: [AnyObject]) {
|
||||
dispatch_async(emitQueue) {
|
||||
if self.status == .Connected {
|
||||
let packet = SocketPacket.packetFromEmit(items, id: ack ?? -1, nsp: self.nsp, ack: true)
|
||||
let str = packet.packetString
|
||||
|
||||
DefaultSocketLogger.Logger.log("Emitting Ack: %@", type: self.logType, args: str)
|
||||
|
||||
self.engine?.send(str, withData: packet.binary)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public func engineDidClose(reason: String) {
|
||||
waitingPackets.removeAll()
|
||||
|
||||
if status != .Disconnected {
|
||||
status = .NotConnected
|
||||
}
|
||||
|
||||
if status == .Disconnected || !reconnects {
|
||||
didDisconnect(reason)
|
||||
} else if !reconnecting {
|
||||
reconnecting = true
|
||||
tryReconnectWithReason(reason)
|
||||
}
|
||||
}
|
||||
|
||||
/// error
|
||||
public func engineDidError(reason: String) {
|
||||
DefaultSocketLogger.Logger.error("%@", type: logType, args: reason)
|
||||
|
||||
handleEvent("error", data: [reason], isInternalMessage: true)
|
||||
}
|
||||
|
||||
// Called when the socket gets an ack for something it sent
|
||||
func handleAck(ack: Int, data: [AnyObject]) {
|
||||
guard status == .Connected else { return }
|
||||
|
||||
DefaultSocketLogger.Logger.log("Handling ack: %@ with data: %@", type: logType, args: ack, data ?? "")
|
||||
|
||||
ackHandlers.executeAck(ack, items: data)
|
||||
}
|
||||
|
||||
/// Causes an event to be handled. Only use if you know what you're doing.
|
||||
public func handleEvent(event: String, data: [AnyObject], isInternalMessage: Bool, withAck ack: Int = -1) {
|
||||
guard status == .Connected || isInternalMessage else {
|
||||
return
|
||||
}
|
||||
|
||||
DefaultSocketLogger.Logger.log("Handling event: %@ with data: %@", type: logType, args: event, data ?? "")
|
||||
|
||||
dispatch_async(handleQueue) {
|
||||
self.anyHandler?(SocketAnyEvent(event: event, items: data))
|
||||
|
||||
for handler in self.handlers where handler.event == event {
|
||||
handler.executeCallback(data, withAck: ack, withSocket: self)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Leaves nsp and goes back to /
|
||||
public func leaveNamespace() {
|
||||
if nsp != "/" {
|
||||
engine?.send("1\(nsp)", withData: [])
|
||||
nsp = "/"
|
||||
}
|
||||
}
|
||||
|
||||
/// Joins namespace
|
||||
public func joinNamespace(namespace: String) {
|
||||
nsp = namespace
|
||||
|
||||
if nsp != "/" {
|
||||
DefaultSocketLogger.Logger.log("Joining namespace", type: logType)
|
||||
engine?.send("0\(nsp)", withData: [])
|
||||
}
|
||||
}
|
||||
|
||||
/// Removes handler(s) based on name
|
||||
public func off(event: String) {
|
||||
DefaultSocketLogger.Logger.log("Removing handler for event: %@", type: logType, args: event)
|
||||
|
||||
handlers = handlers.filter { $0.event != event }
|
||||
}
|
||||
|
||||
/// Removes a handler with the specified UUID gotten from an `on` or `once`
|
||||
public func off(id id: NSUUID) {
|
||||
DefaultSocketLogger.Logger.log("Removing handler with id: %@", type: logType, args: id)
|
||||
|
||||
handlers = handlers.filter { $0.id != id }
|
||||
}
|
||||
|
||||
/// Adds a handler for an event.
|
||||
/// Returns: A unique id for the handler
|
||||
public func on(event: String, callback: NormalCallback) -> NSUUID {
|
||||
DefaultSocketLogger.Logger.log("Adding handler for event: %@", type: logType, args: event)
|
||||
|
||||
let handler = SocketEventHandler(event: event, id: NSUUID(), callback: callback)
|
||||
handlers.append(handler)
|
||||
|
||||
return handler.id
|
||||
}
|
||||
|
||||
/// Adds a single-use handler for an event.
|
||||
/// Returns: A unique id for the handler
|
||||
public func once(event: String, callback: NormalCallback) -> NSUUID {
|
||||
DefaultSocketLogger.Logger.log("Adding once handler for event: %@", type: logType, args: event)
|
||||
|
||||
let id = NSUUID()
|
||||
|
||||
let handler = SocketEventHandler(event: event, id: id) {[weak self] data, ack in
|
||||
guard let this = self else { return }
|
||||
this.off(id: id)
|
||||
callback(data, ack)
|
||||
}
|
||||
|
||||
handlers.append(handler)
|
||||
|
||||
return handler.id
|
||||
}
|
||||
|
||||
/// Adds a handler that will be called on every event.
|
||||
public func onAny(handler: (SocketAnyEvent) -> Void) {
|
||||
anyHandler = handler
|
||||
}
|
||||
|
||||
public func parseEngineMessage(msg: String) {
|
||||
DefaultSocketLogger.Logger.log("Should parse message: %@", type: "SocketIOClient", args: msg)
|
||||
|
||||
dispatch_async(parseQueue) {
|
||||
self.parseSocketMessage(msg)
|
||||
}
|
||||
}
|
||||
|
||||
public func parseEngineBinaryData(data: NSData) {
|
||||
dispatch_async(parseQueue) {
|
||||
self.parseBinaryData(data)
|
||||
}
|
||||
}
|
||||
|
||||
/// Tries to reconnect to the server.
|
||||
public func reconnect() {
|
||||
guard !reconnecting else { return }
|
||||
|
||||
engine?.disconnect("manual reconnect")
|
||||
}
|
||||
|
||||
/// Removes all handlers.
|
||||
/// Can be used after disconnecting to break any potential remaining retain cycles.
|
||||
public func removeAllHandlers() {
|
||||
handlers.removeAll(keepCapacity: false)
|
||||
}
|
||||
|
||||
private func tryReconnectWithReason(reason: String) {
|
||||
if reconnecting {
|
||||
DefaultSocketLogger.Logger.log("Starting reconnect", type: logType)
|
||||
handleEvent("reconnect", data: [reason], isInternalMessage: true)
|
||||
|
||||
_tryReconnect()
|
||||
}
|
||||
}
|
||||
|
||||
private func _tryReconnect() {
|
||||
if !reconnecting {
|
||||
return
|
||||
}
|
||||
|
||||
if reconnectAttempts != -1 && currentReconnectAttempt + 1 > reconnectAttempts || !reconnects {
|
||||
return didDisconnect("Reconnect Failed")
|
||||
}
|
||||
|
||||
DefaultSocketLogger.Logger.log("Trying to reconnect", type: logType)
|
||||
handleEvent("reconnectAttempt", data: [reconnectAttempts - currentReconnectAttempt],
|
||||
isInternalMessage: true)
|
||||
|
||||
currentReconnectAttempt += 1
|
||||
connect()
|
||||
|
||||
let dispatchAfter = dispatch_time(DISPATCH_TIME_NOW, Int64(UInt64(reconnectWait) * NSEC_PER_SEC))
|
||||
|
||||
dispatch_after(dispatchAfter, dispatch_get_main_queue(), _tryReconnect)
|
||||
}
|
||||
}
|
||||
|
||||
// Test extensions
|
||||
extension SocketIOClient {
|
||||
var testHandlers: [SocketEventHandler] {
|
||||
return handlers
|
||||
}
|
||||
|
||||
func setTestable() {
|
||||
status = .Connected
|
||||
}
|
||||
|
||||
func setTestEngine(engine: SocketEngineSpec?) {
|
||||
self.engine = engine
|
||||
}
|
||||
|
||||
func emitTest(event: String, _ data: AnyObject...) {
|
||||
self._emit([event] + data)
|
||||
}
|
||||
}
|
||||
@ -1,220 +0,0 @@
|
||||
//
|
||||
// SocketIOClientOption .swift
|
||||
// Socket.IO-Client-Swift
|
||||
//
|
||||
// Created by Erik Little on 10/17/15.
|
||||
//
|
||||
// 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.
|
||||
|
||||
import Foundation
|
||||
|
||||
protocol ClientOption : CustomStringConvertible, Hashable {
|
||||
func getSocketIOOptionValue() -> AnyObject
|
||||
}
|
||||
|
||||
public enum SocketIOClientOption : ClientOption {
|
||||
case ConnectParams([String: AnyObject])
|
||||
case Cookies([NSHTTPCookie])
|
||||
case DoubleEncodeUTF8(Bool)
|
||||
case ExtraHeaders([String: String])
|
||||
case ForceNew(Bool)
|
||||
case ForcePolling(Bool)
|
||||
case ForceWebsockets(Bool)
|
||||
case HandleQueue(dispatch_queue_t)
|
||||
case Log(Bool)
|
||||
case Logger(SocketLogger)
|
||||
case Nsp(String)
|
||||
case Path(String)
|
||||
case Reconnects(Bool)
|
||||
case ReconnectAttempts(Int)
|
||||
case ReconnectWait(Int)
|
||||
case Secure(Bool)
|
||||
case SelfSigned(Bool)
|
||||
case SessionDelegate(NSURLSessionDelegate)
|
||||
case VoipEnabled(Bool)
|
||||
|
||||
public var description: String {
|
||||
let description: String
|
||||
|
||||
switch self {
|
||||
case .ConnectParams:
|
||||
description = "connectParams"
|
||||
case .Cookies:
|
||||
description = "cookies"
|
||||
case .DoubleEncodeUTF8:
|
||||
description = "doubleEncodeUTF8"
|
||||
case .ExtraHeaders:
|
||||
description = "extraHeaders"
|
||||
case .ForceNew:
|
||||
description = "forceNew"
|
||||
case .ForcePolling:
|
||||
description = "forcePolling"
|
||||
case .ForceWebsockets:
|
||||
description = "forceWebsockets"
|
||||
case .HandleQueue:
|
||||
description = "handleQueue"
|
||||
case .Log:
|
||||
description = "log"
|
||||
case .Logger:
|
||||
description = "logger"
|
||||
case .Nsp:
|
||||
description = "nsp"
|
||||
case .Path:
|
||||
description = "path"
|
||||
case .Reconnects:
|
||||
description = "reconnects"
|
||||
case .ReconnectAttempts:
|
||||
description = "reconnectAttempts"
|
||||
case .ReconnectWait:
|
||||
description = "reconnectWait"
|
||||
case .Secure:
|
||||
description = "secure"
|
||||
case .SelfSigned:
|
||||
description = "selfSigned"
|
||||
case .SessionDelegate:
|
||||
description = "sessionDelegate"
|
||||
case .VoipEnabled:
|
||||
description = "voipEnabled"
|
||||
}
|
||||
|
||||
return description
|
||||
}
|
||||
|
||||
public var hashValue: Int {
|
||||
return description.hashValue
|
||||
}
|
||||
|
||||
func getSocketIOOptionValue() -> AnyObject {
|
||||
let value: AnyObject
|
||||
|
||||
switch self {
|
||||
case let .ConnectParams(params):
|
||||
value = params
|
||||
case let .Cookies(cookies):
|
||||
value = cookies
|
||||
case let .DoubleEncodeUTF8(encode):
|
||||
value = encode
|
||||
case let .ExtraHeaders(headers):
|
||||
value = headers
|
||||
case let .ForceNew(force):
|
||||
value = force
|
||||
case let .ForcePolling(force):
|
||||
value = force
|
||||
case let .ForceWebsockets(force):
|
||||
value = force
|
||||
case let .HandleQueue(queue):
|
||||
value = queue
|
||||
case let .Log(log):
|
||||
value = log
|
||||
case let .Logger(logger):
|
||||
value = logger
|
||||
case let .Nsp(nsp):
|
||||
value = nsp
|
||||
case let .Path(path):
|
||||
value = path
|
||||
case let .Reconnects(reconnects):
|
||||
value = reconnects
|
||||
case let .ReconnectAttempts(attempts):
|
||||
value = attempts
|
||||
case let .ReconnectWait(wait):
|
||||
value = wait
|
||||
case let .Secure(secure):
|
||||
value = secure
|
||||
case let .SelfSigned(signed):
|
||||
value = signed
|
||||
case let .SessionDelegate(delegate):
|
||||
value = delegate
|
||||
case let .VoipEnabled(enabled):
|
||||
value = enabled
|
||||
}
|
||||
|
||||
return value
|
||||
}
|
||||
}
|
||||
|
||||
public func ==(lhs: SocketIOClientOption, rhs: SocketIOClientOption) -> Bool {
|
||||
return lhs.description == rhs.description
|
||||
}
|
||||
|
||||
extension Set where Element : ClientOption {
|
||||
mutating func insertIgnore(element: Element) {
|
||||
if !contains(element) {
|
||||
insert(element)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension NSDictionary {
|
||||
private static func keyValueToSocketIOClientOption(key: String, value: AnyObject) -> SocketIOClientOption? {
|
||||
switch (key, value) {
|
||||
case let ("connectParams", params as [String: AnyObject]):
|
||||
return .ConnectParams(params)
|
||||
case let ("cookies", cookies as [NSHTTPCookie]):
|
||||
return .Cookies(cookies)
|
||||
case let ("doubleEncodeUTF8", encode as Bool):
|
||||
return .DoubleEncodeUTF8(encode)
|
||||
case let ("extraHeaders", headers as [String: String]):
|
||||
return .ExtraHeaders(headers)
|
||||
case let ("forceNew", force as Bool):
|
||||
return .ForceNew(force)
|
||||
case let ("forcePolling", force as Bool):
|
||||
return .ForcePolling(force)
|
||||
case let ("forceWebsockets", force as Bool):
|
||||
return .ForceWebsockets(force)
|
||||
case let ("handleQueue", queue as dispatch_queue_t):
|
||||
return .HandleQueue(queue)
|
||||
case let ("log", log as Bool):
|
||||
return .Log(log)
|
||||
case let ("logger", logger as SocketLogger):
|
||||
return .Logger(logger)
|
||||
case let ("nsp", nsp as String):
|
||||
return .Nsp(nsp)
|
||||
case let ("path", path as String):
|
||||
return .Path(path)
|
||||
case let ("reconnects", reconnects as Bool):
|
||||
return .Reconnects(reconnects)
|
||||
case let ("reconnectAttempts", attempts as Int):
|
||||
return .ReconnectAttempts(attempts)
|
||||
case let ("reconnectWait", wait as Int):
|
||||
return .ReconnectWait(wait)
|
||||
case let ("secure", secure as Bool):
|
||||
return .Secure(secure)
|
||||
case let ("selfSigned", selfSigned as Bool):
|
||||
return .SelfSigned(selfSigned)
|
||||
case let ("sessionDelegate", delegate as NSURLSessionDelegate):
|
||||
return .SessionDelegate(delegate)
|
||||
case let ("voipEnabled", enable as Bool):
|
||||
return .VoipEnabled(enable)
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func toSocketOptionsSet() -> Set<SocketIOClientOption> {
|
||||
var options = Set<SocketIOClientOption>()
|
||||
|
||||
for (rawKey, value) in self {
|
||||
if let key = rawKey as? String, opt = NSDictionary.keyValueToSocketIOClientOption(key, value: value) {
|
||||
options.insertIgnore(opt)
|
||||
}
|
||||
}
|
||||
|
||||
return options
|
||||
}
|
||||
}
|
||||
@ -1,43 +0,0 @@
|
||||
//
|
||||
// SocketIOClientSpec.swift
|
||||
// Socket.IO-Client-Swift
|
||||
//
|
||||
// Created by Erik Little on 1/3/16.
|
||||
//
|
||||
// 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.
|
||||
|
||||
protocol SocketIOClientSpec : class {
|
||||
var nsp: String { get set }
|
||||
var waitingPackets: [SocketPacket] { get set }
|
||||
|
||||
func didConnect()
|
||||
func didDisconnect(reason: String)
|
||||
func didError(reason: String)
|
||||
func handleAck(ack: Int, data: [AnyObject])
|
||||
func handleEvent(event: String, data: [AnyObject], isInternalMessage: Bool, withAck ack: Int)
|
||||
func joinNamespace(namespace: String)
|
||||
}
|
||||
|
||||
extension SocketIOClientSpec {
|
||||
func didError(reason: String) {
|
||||
DefaultSocketLogger.Logger.error("%@", type: "SocketIOClient", args: reason)
|
||||
|
||||
handleEvent("error", data: [reason], isInternalMessage: true, withAck: -1)
|
||||
}
|
||||
}
|
||||
@ -1,264 +0,0 @@
|
||||
//
|
||||
// SocketPacket.swift
|
||||
// Socket.IO-Client-Swift
|
||||
//
|
||||
// Created by Erik Little on 1/18/15.
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
struct SocketPacket {
|
||||
private let placeholders: Int
|
||||
|
||||
private static let logType = "SocketPacket"
|
||||
|
||||
let nsp: String
|
||||
let id: Int
|
||||
let type: PacketType
|
||||
|
||||
enum PacketType: Int {
|
||||
case Connect, Disconnect, Event, Ack, Error, BinaryEvent, BinaryAck
|
||||
}
|
||||
|
||||
var args: [AnyObject] {
|
||||
if type == .Event || type == .BinaryEvent && data.count != 0 {
|
||||
return Array(data.dropFirst())
|
||||
} else {
|
||||
return data
|
||||
}
|
||||
}
|
||||
|
||||
var binary: [NSData]
|
||||
var data: [AnyObject]
|
||||
var description: String {
|
||||
return "SocketPacket {type: \(String(type.rawValue)); data: " +
|
||||
"\(String(data)); id: \(id); placeholders: \(placeholders); nsp: \(nsp)}"
|
||||
}
|
||||
|
||||
var event: String {
|
||||
return String(data[0])
|
||||
}
|
||||
|
||||
var packetString: String {
|
||||
return createPacketString()
|
||||
}
|
||||
|
||||
init(type: SocketPacket.PacketType, data: [AnyObject] = [AnyObject](), id: Int = -1,
|
||||
nsp: String, placeholders: Int = 0, binary: [NSData] = [NSData]()) {
|
||||
self.data = data
|
||||
self.id = id
|
||||
self.nsp = nsp
|
||||
self.type = type
|
||||
self.placeholders = placeholders
|
||||
self.binary = binary
|
||||
}
|
||||
|
||||
mutating func addData(data: NSData) -> Bool {
|
||||
if placeholders == binary.count {
|
||||
return true
|
||||
}
|
||||
|
||||
binary.append(data)
|
||||
|
||||
if placeholders == binary.count {
|
||||
fillInPlaceholders()
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
private func completeMessage(message: String) -> String {
|
||||
let restOfMessage: String
|
||||
|
||||
if data.count == 0 {
|
||||
return message + "[]"
|
||||
}
|
||||
|
||||
do {
|
||||
let jsonSend = try NSJSONSerialization.dataWithJSONObject(data,
|
||||
options: NSJSONWritingOptions(rawValue: 0))
|
||||
guard let jsonString = String(data: jsonSend, encoding: NSUTF8StringEncoding) else {
|
||||
return "[]"
|
||||
}
|
||||
|
||||
restOfMessage = jsonString
|
||||
} catch {
|
||||
DefaultSocketLogger.Logger.error("Error creating JSON object in SocketPacket.completeMessage",
|
||||
type: SocketPacket.logType)
|
||||
|
||||
restOfMessage = "[]"
|
||||
}
|
||||
|
||||
return message + restOfMessage
|
||||
}
|
||||
|
||||
private func createAck() -> String {
|
||||
let message: String
|
||||
|
||||
if type == .Ack {
|
||||
if nsp == "/" {
|
||||
message = "3\(id)"
|
||||
} else {
|
||||
message = "3\(nsp),\(id)"
|
||||
}
|
||||
} else {
|
||||
if nsp == "/" {
|
||||
message = "6\(binary.count)-\(id)"
|
||||
} else {
|
||||
message = "6\(binary.count)-\(nsp),\(id)"
|
||||
}
|
||||
}
|
||||
|
||||
return completeMessage(message)
|
||||
}
|
||||
|
||||
|
||||
private func createMessageForEvent() -> String {
|
||||
let message: String
|
||||
|
||||
if type == .Event {
|
||||
if nsp == "/" {
|
||||
if id == -1 {
|
||||
message = "2"
|
||||
} else {
|
||||
message = "2\(id)"
|
||||
}
|
||||
} else {
|
||||
if id == -1 {
|
||||
message = "2\(nsp),"
|
||||
} else {
|
||||
message = "2\(nsp),\(id)"
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if nsp == "/" {
|
||||
if id == -1 {
|
||||
message = "5\(binary.count)-"
|
||||
} else {
|
||||
message = "5\(binary.count)-\(id)"
|
||||
}
|
||||
} else {
|
||||
if id == -1 {
|
||||
message = "5\(binary.count)-\(nsp),"
|
||||
} else {
|
||||
message = "5\(binary.count)-\(nsp),\(id)"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return completeMessage(message)
|
||||
}
|
||||
|
||||
private func createPacketString() -> String {
|
||||
let str: String
|
||||
|
||||
if type == .Event || type == .BinaryEvent {
|
||||
str = createMessageForEvent()
|
||||
} else {
|
||||
str = createAck()
|
||||
}
|
||||
|
||||
return str
|
||||
}
|
||||
|
||||
// Called when we have all the binary data for a packet
|
||||
// calls _fillInPlaceholders, which replaces placeholders with the
|
||||
// corresponding binary
|
||||
private mutating func fillInPlaceholders() {
|
||||
data = data.map(_fillInPlaceholders)
|
||||
}
|
||||
|
||||
// Helper method that looks for placeholder strings
|
||||
// If object is a collection it will recurse
|
||||
// Returns the object if it is not a placeholder string or the corresponding
|
||||
// binary data
|
||||
private func _fillInPlaceholders(object: AnyObject) -> AnyObject {
|
||||
switch object {
|
||||
case let string as String where string["~~(\\d)"].groups() != nil:
|
||||
return binary[Int(string["~~(\\d)"].groups()![1])!]
|
||||
case let dict as NSDictionary:
|
||||
return dict.reduce(NSMutableDictionary(), combine: {cur, keyValue in
|
||||
cur[keyValue.0 as! NSCopying] = _fillInPlaceholders(keyValue.1)
|
||||
return cur
|
||||
})
|
||||
case let arr as [AnyObject]:
|
||||
return arr.map(_fillInPlaceholders)
|
||||
default:
|
||||
return object
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension SocketPacket {
|
||||
private static func findType(binCount: Int, ack: Bool) -> PacketType {
|
||||
switch binCount {
|
||||
case 0 where !ack:
|
||||
return .Event
|
||||
case 0 where ack:
|
||||
return .Ack
|
||||
case _ where !ack:
|
||||
return .BinaryEvent
|
||||
case _ where ack:
|
||||
return .BinaryAck
|
||||
default:
|
||||
return .Error
|
||||
}
|
||||
}
|
||||
|
||||
static func packetFromEmit(items: [AnyObject], id: Int, nsp: String, ack: Bool) -> SocketPacket {
|
||||
let (parsedData, binary) = deconstructData(items)
|
||||
let packet = SocketPacket(type: findType(binary.count, ack: ack), data: parsedData,
|
||||
id: id, nsp: nsp, placeholders: -1, binary: binary)
|
||||
|
||||
return packet
|
||||
}
|
||||
}
|
||||
|
||||
private extension SocketPacket {
|
||||
// Recursive function that looks for NSData in collections
|
||||
static func shred(data: AnyObject, inout binary: [NSData]) -> AnyObject {
|
||||
let placeholder = ["_placeholder": true, "num": binary.count]
|
||||
|
||||
switch data {
|
||||
case let bin as NSData:
|
||||
binary.append(bin)
|
||||
return placeholder
|
||||
case let arr as [AnyObject]:
|
||||
return arr.map({shred($0, binary: &binary)})
|
||||
case let dict as NSDictionary:
|
||||
return dict.reduce(NSMutableDictionary(), combine: {cur, keyValue in
|
||||
cur[keyValue.0 as! NSCopying] = shred(keyValue.1, binary: &binary)
|
||||
return cur
|
||||
})
|
||||
default:
|
||||
return data
|
||||
}
|
||||
}
|
||||
|
||||
// Removes binary data from emit data
|
||||
// Returns a type containing the de-binaryed data and the binary
|
||||
static func deconstructData(data: [AnyObject]) -> ([AnyObject], [NSData]) {
|
||||
var binary = [NSData]()
|
||||
|
||||
return (data.map({shred($0, binary: &binary)}), binary)
|
||||
}
|
||||
}
|
||||
@ -1,182 +0,0 @@
|
||||
//
|
||||
// SocketParsable.swift
|
||||
// Socket.IO-Client-Swift
|
||||
//
|
||||
// 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.
|
||||
|
||||
import Foundation
|
||||
|
||||
protocol SocketParsable : SocketIOClientSpec {
|
||||
func parseBinaryData(data: NSData)
|
||||
func parseSocketMessage(message: String)
|
||||
}
|
||||
|
||||
extension SocketParsable {
|
||||
private func isCorrectNamespace(nsp: String) -> Bool {
|
||||
return nsp == self.nsp
|
||||
}
|
||||
|
||||
private func handleConnect(p: SocketPacket) {
|
||||
if p.nsp == "/" && nsp != "/" {
|
||||
joinNamespace(nsp)
|
||||
} else if p.nsp != "/" && nsp == "/" {
|
||||
didConnect()
|
||||
} else {
|
||||
didConnect()
|
||||
}
|
||||
}
|
||||
|
||||
private func handlePacket(pack: SocketPacket) {
|
||||
switch pack.type {
|
||||
case .Event where isCorrectNamespace(pack.nsp):
|
||||
handleEvent(pack.event, data: pack.args, isInternalMessage: false, withAck: pack.id)
|
||||
case .Ack where isCorrectNamespace(pack.nsp):
|
||||
handleAck(pack.id, data: pack.data)
|
||||
case .BinaryEvent where isCorrectNamespace(pack.nsp):
|
||||
waitingPackets.append(pack)
|
||||
case .BinaryAck where isCorrectNamespace(pack.nsp):
|
||||
waitingPackets.append(pack)
|
||||
case .Connect:
|
||||
handleConnect(pack)
|
||||
case .Disconnect:
|
||||
didDisconnect("Got Disconnect")
|
||||
case .Error:
|
||||
handleEvent("error", data: pack.data, isInternalMessage: true, withAck: pack.id)
|
||||
default:
|
||||
DefaultSocketLogger.Logger.log("Got invalid packet: %@", type: "SocketParser", args: pack.description)
|
||||
}
|
||||
}
|
||||
|
||||
/// Parses a messsage from the engine. Returning either a string error or a complete SocketPacket
|
||||
func parseString(message: String) -> Either<String, SocketPacket> {
|
||||
var parser = SocketStringReader(message: message)
|
||||
|
||||
guard let type = SocketPacket.PacketType(rawValue: Int(parser.read(1)) ?? -1) else {
|
||||
return .Left("Invalid packet type")
|
||||
}
|
||||
|
||||
if !parser.hasNext {
|
||||
return .Right(SocketPacket(type: type, nsp: "/"))
|
||||
}
|
||||
|
||||
var namespace = "/"
|
||||
var placeholders = -1
|
||||
|
||||
if type == .BinaryEvent || type == .BinaryAck {
|
||||
if let holders = Int(parser.readUntilStringOccurence("-")) {
|
||||
placeholders = holders
|
||||
} else {
|
||||
return .Left("Invalid packet")
|
||||
}
|
||||
}
|
||||
|
||||
if parser.currentCharacter == "/" {
|
||||
namespace = parser.readUntilStringOccurence(",") ?? parser.readUntilEnd()
|
||||
}
|
||||
|
||||
if !parser.hasNext {
|
||||
return .Right(SocketPacket(type: type, id: -1,
|
||||
nsp: namespace ?? "/", placeholders: placeholders))
|
||||
}
|
||||
|
||||
var idString = ""
|
||||
|
||||
if type == .Error {
|
||||
parser.advanceIndexBy(-1)
|
||||
}
|
||||
|
||||
while parser.hasNext && type != .Error {
|
||||
if let int = Int(parser.read(1)) {
|
||||
idString += String(int)
|
||||
} else {
|
||||
parser.advanceIndexBy(-2)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
let d = message[parser.currentIndex.advancedBy(1)..<message.endIndex]
|
||||
let noPlaceholders = d["(\\{\"_placeholder\":true,\"num\":(\\d*)\\})"] <~ "\"~~$2\""
|
||||
|
||||
switch parseData(noPlaceholders) {
|
||||
case let .Left(err):
|
||||
// Errors aren't always enclosed in an array
|
||||
if case let .Right(data) = parseData("\([noPlaceholders as AnyObject])") {
|
||||
return .Right(SocketPacket(type: type, data: data, id: Int(idString) ?? -1,
|
||||
nsp: namespace, placeholders: placeholders))
|
||||
} else {
|
||||
return .Left(err)
|
||||
}
|
||||
case let .Right(data):
|
||||
return .Right(SocketPacket(type: type, data: data, id: Int(idString) ?? -1,
|
||||
nsp: namespace, placeholders: placeholders))
|
||||
}
|
||||
}
|
||||
|
||||
// Parses data for events
|
||||
private func parseData(data: String) -> Either<String, [AnyObject]> {
|
||||
let stringData = data.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)
|
||||
|
||||
do {
|
||||
if let arr = try NSJSONSerialization.JSONObjectWithData(stringData!,
|
||||
options: NSJSONReadingOptions.MutableContainers) as? [AnyObject] {
|
||||
return .Right(arr)
|
||||
} else {
|
||||
return .Left("Expected data array")
|
||||
}
|
||||
} catch {
|
||||
return .Left("Error parsing data for packet")
|
||||
}
|
||||
}
|
||||
|
||||
// Parses messages recieved
|
||||
func parseSocketMessage(message: String) {
|
||||
guard !message.isEmpty else { return }
|
||||
|
||||
DefaultSocketLogger.Logger.log("Parsing %@", type: "SocketParser", args: message)
|
||||
|
||||
switch parseString(message) {
|
||||
case let .Left(err):
|
||||
DefaultSocketLogger.Logger.error("\(err): %@", type: "SocketParser", args: message)
|
||||
case let .Right(pack):
|
||||
DefaultSocketLogger.Logger.log("Decoded packet as: %@", type: "SocketParser", args: pack.description)
|
||||
handlePacket(pack)
|
||||
}
|
||||
}
|
||||
|
||||
func parseBinaryData(data: NSData) {
|
||||
guard !waitingPackets.isEmpty else {
|
||||
DefaultSocketLogger.Logger.error("Got data when not remaking packet", type: "SocketParser")
|
||||
return
|
||||
}
|
||||
|
||||
// Should execute event?
|
||||
guard waitingPackets[waitingPackets.count - 1].addData(data) else {
|
||||
return
|
||||
}
|
||||
|
||||
let packet = waitingPackets.removeLast()
|
||||
|
||||
if packet.type != .BinaryAck {
|
||||
handleEvent(packet.event, data: packet.args ?? [],
|
||||
isInternalMessage: false, withAck: packet.id)
|
||||
} else {
|
||||
handleAck(packet.id, data: packet.args)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,34 +0,0 @@
|
||||
//
|
||||
// SocketTypes.swift
|
||||
// Socket.IO-Client-Swift
|
||||
//
|
||||
// Created by Erik Little on 4/8/15.
|
||||
//
|
||||
// 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.
|
||||
|
||||
import Foundation
|
||||
|
||||
public typealias AckCallback = ([AnyObject]) -> Void
|
||||
public typealias NormalCallback = ([AnyObject], SocketAckEmitter) -> Void
|
||||
public typealias OnAckCallback = (timeoutAfter: UInt64, callback: AckCallback) -> Void
|
||||
|
||||
enum Either<E, V> {
|
||||
case Left(E)
|
||||
case Right(V)
|
||||
}
|
||||
@ -1,31 +0,0 @@
|
||||
//
|
||||
// String.swift
|
||||
// Socket.IO-Client-Swift
|
||||
//
|
||||
// Created by Yannick Loriot on 5/4/16.
|
||||
//
|
||||
// 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.
|
||||
|
||||
import Foundation
|
||||
|
||||
extension String {
|
||||
func urlEncode() -> String? {
|
||||
return stringByAddingPercentEncodingWithAllowedCharacters(.allowedURLCharacterSet)
|
||||
}
|
||||
}
|
||||
@ -1,195 +0,0 @@
|
||||
//
|
||||
// SwiftRegex.swift
|
||||
// SwiftRegex
|
||||
//
|
||||
// Created by John Holdsworth on 26/06/2014.
|
||||
// Copyright (c) 2014 John Holdsworth.
|
||||
//
|
||||
// $Id: //depot/SwiftRegex/SwiftRegex.swift#37 $
|
||||
//
|
||||
// This code is in the public domain from:
|
||||
// https://github.com/johnno1962/SwiftRegex
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
infix operator <~ { associativity none precedence 130 }
|
||||
|
||||
private let lock = dispatch_semaphore_create(1)
|
||||
private var swiftRegexCache = [String: NSRegularExpression]()
|
||||
|
||||
internal final class SwiftRegex : NSObject, BooleanType {
|
||||
var target: String
|
||||
var regex: NSRegularExpression
|
||||
|
||||
init(target:String, pattern:String, options:NSRegularExpressionOptions?) {
|
||||
self.target = target
|
||||
|
||||
if dispatch_semaphore_wait(lock, dispatch_time(DISPATCH_TIME_NOW, Int64(10 * NSEC_PER_MSEC))) != 0 {
|
||||
do {
|
||||
let regex = try NSRegularExpression(pattern: pattern, options:
|
||||
NSRegularExpressionOptions.DotMatchesLineSeparators)
|
||||
self.regex = regex
|
||||
} catch let error as NSError {
|
||||
SwiftRegex.failure("Error in pattern: \(pattern) - \(error)")
|
||||
self.regex = NSRegularExpression()
|
||||
}
|
||||
|
||||
super.init()
|
||||
return
|
||||
}
|
||||
|
||||
if let regex = swiftRegexCache[pattern] {
|
||||
self.regex = regex
|
||||
} else {
|
||||
do {
|
||||
let regex = try NSRegularExpression(pattern: pattern, options:
|
||||
NSRegularExpressionOptions.DotMatchesLineSeparators)
|
||||
swiftRegexCache[pattern] = regex
|
||||
self.regex = regex
|
||||
} catch let error as NSError {
|
||||
SwiftRegex.failure("Error in pattern: \(pattern) - \(error)")
|
||||
self.regex = NSRegularExpression()
|
||||
}
|
||||
}
|
||||
dispatch_semaphore_signal(lock)
|
||||
super.init()
|
||||
}
|
||||
|
||||
private static func failure(message: String) {
|
||||
fatalError("SwiftRegex: \(message)")
|
||||
}
|
||||
|
||||
private var targetRange: NSRange {
|
||||
return NSRange(location: 0,length: target.utf16.count)
|
||||
}
|
||||
|
||||
private func substring(range: NSRange) -> String? {
|
||||
if range.location != NSNotFound {
|
||||
return (target as NSString).substringWithRange(range)
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func doesMatch(options: NSMatchingOptions!) -> Bool {
|
||||
return range(options).location != NSNotFound
|
||||
}
|
||||
|
||||
func range(options: NSMatchingOptions) -> NSRange {
|
||||
return regex.rangeOfFirstMatchInString(target as String, options: [], range: targetRange)
|
||||
}
|
||||
|
||||
func match(options: NSMatchingOptions) -> String? {
|
||||
return substring(range(options))
|
||||
}
|
||||
|
||||
func groups() -> [String]? {
|
||||
return groupsForMatch(regex.firstMatchInString(target as String, options:
|
||||
NSMatchingOptions.WithoutAnchoringBounds, range: targetRange))
|
||||
}
|
||||
|
||||
private func groupsForMatch(match: NSTextCheckingResult?) -> [String]? {
|
||||
guard let match = match else {
|
||||
return nil
|
||||
}
|
||||
var groups = [String]()
|
||||
for groupno in 0...regex.numberOfCaptureGroups {
|
||||
if let group = substring(match.rangeAtIndex(groupno)) {
|
||||
groups += [group]
|
||||
} else {
|
||||
groups += ["_"] // avoids bridging problems
|
||||
}
|
||||
}
|
||||
return groups
|
||||
}
|
||||
|
||||
subscript(groupno: Int) -> String? {
|
||||
get {
|
||||
return groups()?[groupno]
|
||||
}
|
||||
|
||||
set(newValue) {
|
||||
if newValue == nil {
|
||||
return
|
||||
}
|
||||
|
||||
for match in Array(matchResults().reverse()) {
|
||||
let replacement = regex.replacementStringForResult(match,
|
||||
inString: target as String, offset: 0, template: newValue!)
|
||||
let mut = NSMutableString(string: target)
|
||||
mut.replaceCharactersInRange(match.rangeAtIndex(groupno), withString: replacement)
|
||||
|
||||
target = mut as String
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func matchResults() -> [NSTextCheckingResult] {
|
||||
let matches = regex.matchesInString(target as String, options:
|
||||
NSMatchingOptions.WithoutAnchoringBounds, range: targetRange)
|
||||
as [NSTextCheckingResult]
|
||||
|
||||
return matches
|
||||
}
|
||||
|
||||
func ranges() -> [NSRange] {
|
||||
return matchResults().map { $0.range }
|
||||
}
|
||||
|
||||
func matches() -> [String] {
|
||||
return matchResults().map( { self.substring($0.range)!})
|
||||
}
|
||||
|
||||
func allGroups() -> [[String]?] {
|
||||
return matchResults().map { self.groupsForMatch($0) }
|
||||
}
|
||||
|
||||
func dictionary(options: NSMatchingOptions!) -> Dictionary<String,String> {
|
||||
var out = Dictionary<String,String>()
|
||||
for match in matchResults() {
|
||||
out[substring(match.rangeAtIndex(1))!] = substring(match.rangeAtIndex(2))!
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func substituteMatches(substitution: ((NSTextCheckingResult, UnsafeMutablePointer<ObjCBool>) -> String),
|
||||
options:NSMatchingOptions) -> String {
|
||||
let out = NSMutableString()
|
||||
var pos = 0
|
||||
|
||||
regex.enumerateMatchesInString(target as String, options: options, range: targetRange ) {match, flags, stop in
|
||||
let matchRange = match!.range
|
||||
out.appendString( self.substring(NSRange(location:pos, length:matchRange.location-pos))!)
|
||||
out.appendString( substitution(match!, stop) )
|
||||
pos = matchRange.location + matchRange.length
|
||||
}
|
||||
|
||||
out.appendString(substring(NSRange(location:pos, length:targetRange.length-pos))!)
|
||||
|
||||
return out as String
|
||||
}
|
||||
|
||||
var boolValue: Bool {
|
||||
return doesMatch(nil)
|
||||
}
|
||||
}
|
||||
|
||||
extension String {
|
||||
subscript(pattern: String, options: NSRegularExpressionOptions) -> SwiftRegex {
|
||||
return SwiftRegex(target: self, pattern: pattern, options: options)
|
||||
}
|
||||
}
|
||||
|
||||
extension String {
|
||||
subscript(pattern: String) -> SwiftRegex {
|
||||
return SwiftRegex(target: self, pattern: pattern, options: nil)
|
||||
}
|
||||
}
|
||||
|
||||
func <~ (left: SwiftRegex, right: String) -> String {
|
||||
return left.substituteMatches({match, stop in
|
||||
return left.regex.replacementStringForResult( match,
|
||||
inString: left.target as String, offset: 0, template: right )
|
||||
}, options: [])
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
50
Tests/TestSocketIO/SocketAckManagerTest.swift
Normal file
50
Tests/TestSocketIO/SocketAckManagerTest.swift
Normal file
@ -0,0 +1,50 @@
|
||||
//
|
||||
// SocketAckManagerTest.swift
|
||||
// Socket.IO-Client-Swift
|
||||
//
|
||||
// Created by Lukas Schmidt on 04.09.15.
|
||||
//
|
||||
//
|
||||
|
||||
import XCTest
|
||||
@testable import SocketIO
|
||||
|
||||
class SocketAckManagerTest : XCTestCase {
|
||||
var ackManager = SocketAckManager()
|
||||
|
||||
func testAddAcks() {
|
||||
let callbackExpection = expectation(description: "callbackExpection")
|
||||
let itemsArray = ["Hi", "ho"]
|
||||
|
||||
func callback(_ items: [Any]) {
|
||||
callbackExpection.fulfill()
|
||||
}
|
||||
|
||||
ackManager.addAck(1, callback: callback)
|
||||
ackManager.executeAck(1, with: itemsArray)
|
||||
|
||||
waitForExpectations(timeout: 3.0, handler: nil)
|
||||
}
|
||||
|
||||
func testManagerTimeoutAck() {
|
||||
let callbackExpection = expectation(description: "Manager should timeout ack with noAck status")
|
||||
|
||||
func callback(_ items: [Any]) {
|
||||
XCTAssertEqual(items.count, 1, "Timed out ack should have one value")
|
||||
guard let timeoutReason = items[0] as? String else {
|
||||
XCTFail("Timeout reason should be a string")
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
XCTAssert(timeoutReason == SocketAckStatus.noAck)
|
||||
|
||||
callbackExpection.fulfill()
|
||||
}
|
||||
|
||||
ackManager.addAck(1, callback: callback)
|
||||
ackManager.timeoutAck(1)
|
||||
|
||||
waitForExpectations(timeout: 0.2, handler: nil)
|
||||
}
|
||||
}
|
||||
215
Tests/TestSocketIO/SocketBasicPacketTest.swift
Normal file
215
Tests/TestSocketIO/SocketBasicPacketTest.swift
Normal file
@ -0,0 +1,215 @@
|
||||
//
|
||||
// SocketBasicPacketTest.swift
|
||||
// Socket.IO-Client-Swift
|
||||
//
|
||||
// Created by Erik Little on 10/7/15.
|
||||
//
|
||||
//
|
||||
|
||||
import XCTest
|
||||
@testable import SocketIO
|
||||
|
||||
class SocketBasicPacketTest : XCTestCase {
|
||||
func testEmptyEmit() {
|
||||
let sendData = ["test"]
|
||||
let packetStr = SocketPacket.packetFromEmit(sendData, id: -1, nsp: "/", ack: false).packetString
|
||||
let parsed = parser.parseSocketMessage(packetStr)!
|
||||
|
||||
XCTAssertEqual(parsed.type, .event)
|
||||
XCTAssertTrue(compareAnyArray(input: parsed.data, expected: sendData))
|
||||
}
|
||||
|
||||
func testNullEmit() {
|
||||
let sendData: [Any] = ["test", NSNull()]
|
||||
let packetStr = SocketPacket.packetFromEmit(sendData, id: -1, nsp: "/", ack: false).packetString
|
||||
let parsed = parser.parseSocketMessage(packetStr)!
|
||||
|
||||
XCTAssertEqual(parsed.type, .event)
|
||||
XCTAssertTrue(compareAnyArray(input: parsed.data, expected: sendData))
|
||||
}
|
||||
|
||||
func testStringEmit() {
|
||||
let sendData = ["test", "foo bar"]
|
||||
let packetStr = SocketPacket.packetFromEmit(sendData, id: -1, nsp: "/", ack: false).packetString
|
||||
let parsed = parser.parseSocketMessage(packetStr)!
|
||||
|
||||
XCTAssertEqual(parsed.type, .event)
|
||||
XCTAssertTrue(compareAnyArray(input: parsed.data, expected: sendData))
|
||||
}
|
||||
|
||||
func testStringEmitWithQuotes() {
|
||||
let sendData = ["test", "\"he\"llo world\""]
|
||||
let packetStr = SocketPacket.packetFromEmit(sendData, id: -1, nsp: "/", ack: false).packetString
|
||||
let parsed = parser.parseSocketMessage(packetStr)!
|
||||
|
||||
XCTAssertEqual(parsed.type, .event)
|
||||
XCTAssertTrue(compareAnyArray(input: parsed.data, expected: sendData))
|
||||
}
|
||||
|
||||
func testJSONEmit() {
|
||||
let sendData: [Any] = ["test", ["foobar": true, "hello": 1, "test": "hello", "null": NSNull()]]
|
||||
let packetStr = SocketPacket.packetFromEmit(sendData, id: -1, nsp: "/", ack: false).packetString
|
||||
let parsed = parser.parseSocketMessage(packetStr)!
|
||||
|
||||
XCTAssertEqual(parsed.type, .event)
|
||||
XCTAssertTrue(compareAnyArray(input: parsed.data, expected: sendData))
|
||||
}
|
||||
|
||||
func testArrayEmit() {
|
||||
let sendData: [Any] = ["test", ["hello", 1, ["test": "test"]]]
|
||||
let packetStr = SocketPacket.packetFromEmit(sendData, id: -1, nsp: "/", ack: false).packetString
|
||||
let parsed = parser.parseSocketMessage(packetStr)!
|
||||
|
||||
XCTAssertEqual(parsed.type, .event)
|
||||
XCTAssertTrue(compareAnyArray(input: parsed.data, expected: sendData))
|
||||
}
|
||||
|
||||
func testBinaryEmit() {
|
||||
let sendData: [Any] = ["test", data]
|
||||
let packet = SocketPacket.packetFromEmit(sendData, id: -1, nsp: "/", ack: false)
|
||||
let parsed = parser.parseSocketMessage(packet.packetString)!
|
||||
|
||||
XCTAssertEqual(parsed.type, .binaryEvent)
|
||||
XCTAssertEqual(packet.binary, [data])
|
||||
XCTAssertTrue(compareAnyArray(input: parsed.data, expected: [
|
||||
"test",
|
||||
["_placeholder": true, "num": 0]
|
||||
]))
|
||||
}
|
||||
|
||||
func testMultipleBinaryEmit() {
|
||||
let sendData: [Any] = ["test", ["data1": data, "data2": data2] as NSDictionary]
|
||||
let packet = SocketPacket.packetFromEmit(sendData, id: -1, nsp: "/", ack: false)
|
||||
let parsed = parser.parseSocketMessage(packet.packetString)!
|
||||
|
||||
XCTAssertEqual(parsed.type, .binaryEvent)
|
||||
|
||||
let binaryObj = parsed.data[1] as! [String: Any]
|
||||
let data1Loc = (binaryObj["data1"] as! [String: Any])["num"] as! Int
|
||||
let data2Loc = (binaryObj["data2"] as! [String: Any])["num"] as! Int
|
||||
|
||||
XCTAssertEqual(packet.binary[data1Loc], data)
|
||||
XCTAssertEqual(packet.binary[data2Loc], data2)
|
||||
}
|
||||
|
||||
func testEmitWithAck() {
|
||||
let sendData = ["test"]
|
||||
let packetStr = SocketPacket.packetFromEmit(sendData, id: 0, nsp: "/", ack: false).packetString
|
||||
let parsed = parser.parseSocketMessage(packetStr)!
|
||||
|
||||
XCTAssertEqual(parsed.type, .event)
|
||||
XCTAssertEqual(parsed.id, 0)
|
||||
XCTAssertTrue(compareAnyArray(input: parsed.data, expected: sendData))
|
||||
}
|
||||
|
||||
func testEmitDataWithAck() {
|
||||
let sendData: [Any] = ["test", data]
|
||||
let packet = SocketPacket.packetFromEmit(sendData, id: 0, nsp: "/", ack: false)
|
||||
let parsed = parser.parseSocketMessage(packet.packetString)!
|
||||
|
||||
XCTAssertEqual(parsed.type, .binaryEvent)
|
||||
XCTAssertEqual(parsed.id, 0)
|
||||
XCTAssertTrue(compareAnyArray(input: parsed.data, expected: [
|
||||
"test",
|
||||
["_placeholder": true, "num": 0]
|
||||
]))
|
||||
XCTAssertEqual(packet.binary, [data])
|
||||
}
|
||||
|
||||
// Acks
|
||||
func testEmptyAck() {
|
||||
let packetStr = SocketPacket.packetFromEmit([], id: 0, nsp: "/", ack: true).packetString
|
||||
let parsed = parser.parseSocketMessage(packetStr)!
|
||||
|
||||
XCTAssertEqual(parsed.type, .ack)
|
||||
XCTAssertEqual(parsed.id, 0)
|
||||
XCTAssertTrue(compareAnyArray(input: parsed.data, expected: []))
|
||||
}
|
||||
|
||||
func testNullAck() {
|
||||
let sendData = [NSNull()]
|
||||
let packetStr = SocketPacket.packetFromEmit(sendData, id: 0, nsp: "/", ack: true).packetString
|
||||
let parsed = parser.parseSocketMessage(packetStr)!
|
||||
|
||||
XCTAssertEqual(parsed.type, .ack)
|
||||
XCTAssertEqual(parsed.id, 0)
|
||||
XCTAssertTrue(compareAnyArray(input: parsed.data, expected: sendData))
|
||||
}
|
||||
|
||||
func testStringAck() {
|
||||
let sendData = ["test"]
|
||||
let packetStr = SocketPacket.packetFromEmit(sendData, id: 0, nsp: "/", ack: true).packetString
|
||||
let parsed = parser.parseSocketMessage(packetStr)!
|
||||
|
||||
XCTAssertEqual(parsed.type, .ack)
|
||||
XCTAssertEqual(parsed.id, 0)
|
||||
XCTAssertTrue(compareAnyArray(input: parsed.data, expected: sendData))
|
||||
}
|
||||
|
||||
func testJSONAck() {
|
||||
let sendData = [["foobar": true, "hello": 1, "test": "hello", "null": NSNull()]]
|
||||
let packetStr = SocketPacket.packetFromEmit(sendData, id: 0, nsp: "/", ack: true).packetString
|
||||
let parsed = parser.parseSocketMessage(packetStr)!
|
||||
|
||||
XCTAssertEqual(parsed.type, .ack)
|
||||
XCTAssertEqual(parsed.id, 0)
|
||||
XCTAssertTrue(compareAnyArray(input: parsed.data, expected: sendData))
|
||||
}
|
||||
|
||||
func testBinaryAck() {
|
||||
let sendData = [data]
|
||||
let packet = SocketPacket.packetFromEmit(sendData, id: 0, nsp: "/", ack: true)
|
||||
let parsed = parser.parseSocketMessage(packet.packetString)!
|
||||
|
||||
XCTAssertEqual(parsed.type, .binaryAck)
|
||||
XCTAssertEqual(packet.binary, [data])
|
||||
XCTAssertEqual(parsed.id, 0)
|
||||
XCTAssertTrue(compareAnyArray(input: parsed.data, expected: [
|
||||
["_placeholder": true, "num": 0]
|
||||
]))
|
||||
}
|
||||
|
||||
func testMultipleBinaryAck() {
|
||||
let sendData = [["data1": data, "data2": data2]]
|
||||
let packet = SocketPacket.packetFromEmit(sendData, id: 0, nsp: "/", ack: true)
|
||||
let parsed = parser.parseSocketMessage(packet.packetString)!
|
||||
|
||||
XCTAssertEqual(parsed.id, 0)
|
||||
XCTAssertEqual(parsed.type, .binaryAck)
|
||||
|
||||
let binaryObj = parsed.data[0] as! [String: Any]
|
||||
let data1Loc = (binaryObj["data1"] as! [String: Any])["num"] as! Int
|
||||
let data2Loc = (binaryObj["data2"] as! [String: Any])["num"] as! Int
|
||||
|
||||
XCTAssertEqual(packet.binary[data1Loc], data)
|
||||
XCTAssertEqual(packet.binary[data2Loc], data2)
|
||||
}
|
||||
|
||||
func testBinaryStringPlaceholderInMessage() {
|
||||
let engineString = "52-[\"test\",\"~~0\",{\"num\":0,\"_placeholder\":true},{\"_placeholder\":true,\"num\":1}]"
|
||||
let manager = SocketManager(socketURL: URL(string: "http://localhost/")!)
|
||||
|
||||
var packet = try! manager.parseString(engineString)
|
||||
|
||||
XCTAssertEqual(packet.event, "test")
|
||||
_ = packet.addData(data)
|
||||
_ = packet.addData(data2)
|
||||
XCTAssertEqual(packet.args[0] as? String, "~~0")
|
||||
}
|
||||
|
||||
private func compareAnyArray(input: [Any], expected: [Any]) -> Bool {
|
||||
guard input.count == expected.count else { return false }
|
||||
|
||||
return (input as NSArray).isEqual(to: expected)
|
||||
}
|
||||
|
||||
let data = "test".data(using: String.Encoding.utf8)!
|
||||
let data2 = "test2".data(using: String.Encoding.utf8)!
|
||||
var parser: SocketParsable!
|
||||
|
||||
override func setUp() {
|
||||
super.setUp()
|
||||
|
||||
parser = SocketManager(socketURL: URL(string: "http://localhost")!)
|
||||
}
|
||||
}
|
||||
229
Tests/TestSocketIO/SocketEngineTest.swift
Normal file
229
Tests/TestSocketIO/SocketEngineTest.swift
Normal file
@ -0,0 +1,229 @@
|
||||
//
|
||||
// SocketEngineTest.swift
|
||||
// Socket.IO-Client-Swift
|
||||
//
|
||||
// Created by Erik Little on 10/15/15.
|
||||
//
|
||||
//
|
||||
|
||||
import XCTest
|
||||
@testable import SocketIO
|
||||
|
||||
class SocketEngineTest: XCTestCase {
|
||||
func testBasicPollingMessageV3() {
|
||||
let expect = expectation(description: "Basic polling test v3")
|
||||
|
||||
socket.on("blankTest") {data, ack in
|
||||
expect.fulfill()
|
||||
}
|
||||
|
||||
engine.setConfigs([.version(.two)])
|
||||
engine.parsePollingMessage("15:42[\"blankTest\"]")
|
||||
|
||||
waitForExpectations(timeout: 3, handler: nil)
|
||||
}
|
||||
|
||||
func testBasicPollingMessage() {
|
||||
let expect = expectation(description: "Basic polling test")
|
||||
socket.on("blankTest") {data, ack in
|
||||
expect.fulfill()
|
||||
}
|
||||
|
||||
engine.parsePollingMessage("42[\"blankTest\"]")
|
||||
waitForExpectations(timeout: 3, handler: nil)
|
||||
}
|
||||
|
||||
func testTwoPacketsInOnePollTest() {
|
||||
let finalExpectation = expectation(description: "Final packet in poll test")
|
||||
var gotBlank = false
|
||||
|
||||
socket.on("blankTest") {data, ack in
|
||||
gotBlank = true
|
||||
}
|
||||
|
||||
socket.on("stringTest") {data, ack in
|
||||
if let str = data[0] as? String, gotBlank {
|
||||
if str == "hello" {
|
||||
finalExpectation.fulfill()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
engine.parsePollingMessage("42[\"blankTest\"]\u{1e}42[\"stringTest\",\"hello\"]")
|
||||
waitForExpectations(timeout: 3, handler: nil)
|
||||
}
|
||||
|
||||
func testEngineDoesErrorOnUnknownTransport() {
|
||||
let finalExpectation = expectation(description: "Unknown Transport")
|
||||
|
||||
socket.on("error") {data, ack in
|
||||
if let error = data[0] as? String, error == "Unknown transport" {
|
||||
finalExpectation.fulfill()
|
||||
}
|
||||
}
|
||||
|
||||
engine.parseEngineMessage("{\"code\": 0, \"message\": \"Unknown transport\"}")
|
||||
waitForExpectations(timeout: 3, handler: nil)
|
||||
}
|
||||
|
||||
func testEngineDoesErrorOnUnknownMessage() {
|
||||
let finalExpectation = expectation(description: "Engine Errors")
|
||||
|
||||
socket.on("error") {data, ack in
|
||||
finalExpectation.fulfill()
|
||||
}
|
||||
|
||||
engine.parseEngineMessage("afafafda")
|
||||
waitForExpectations(timeout: 3, handler: nil)
|
||||
}
|
||||
|
||||
func testEngineDecodesUTF8Properly() {
|
||||
let expect = expectation(description: "Engine Decodes utf8")
|
||||
|
||||
socket.on("stringTest") {data, ack in
|
||||
XCTAssertEqual(data[0] as? String, "lïne one\nlīne \rtwo𦅙𦅛", "Failed string test")
|
||||
expect.fulfill()
|
||||
}
|
||||
|
||||
let stringMessage = "42[\"stringTest\",\"lïne one\\nlīne \\rtwo𦅙𦅛\"]"
|
||||
|
||||
engine.parsePollingMessage("\(stringMessage)")
|
||||
waitForExpectations(timeout: 3, handler: nil)
|
||||
}
|
||||
|
||||
func testEncodeURLProperly() {
|
||||
engine.connectParams = [
|
||||
"created": "2016-05-04T18:31:15+0200"
|
||||
]
|
||||
|
||||
XCTAssertEqual(engine.urlPolling.query, "transport=polling&b64=1&created=2016-05-04T18%3A31%3A15%2B0200&EIO=4")
|
||||
XCTAssertEqual(engine.urlWebSocket.query, "transport=websocket&created=2016-05-04T18%3A31%3A15%2B0200&EIO=4")
|
||||
|
||||
engine.connectParams = [
|
||||
"forbidden": "!*'();:@&=+$,/?%#[]\" {}^|"
|
||||
]
|
||||
|
||||
XCTAssertEqual(engine.urlPolling.query, "transport=polling&b64=1&forbidden=%21%2A%27%28%29%3B%3A%40%26%3D%2B%24%2C%2F%3F%25%23%5B%5D%22%20%7B%7D%5E%7C&EIO=4")
|
||||
XCTAssertEqual(engine.urlWebSocket.query, "transport=websocket&forbidden=%21%2A%27%28%29%3B%3A%40%26%3D%2B%24%2C%2F%3F%25%23%5B%5D%22%20%7B%7D%5E%7C&EIO=4")
|
||||
}
|
||||
|
||||
func testBase64Data() {
|
||||
let expect = expectation(description: "Engine Decodes base64 data")
|
||||
let b64String = "baGVsbG8NCg=="
|
||||
let packetString = "451-[\"test\",{\"test\":{\"_placeholder\":true,\"num\":0}}]"
|
||||
|
||||
socket.on("test") {data, ack in
|
||||
if let data = data[0] as? Data, let string = String(data: data, encoding: .utf8) {
|
||||
XCTAssertEqual(string, "hello")
|
||||
}
|
||||
|
||||
expect.fulfill()
|
||||
}
|
||||
|
||||
engine.parseEngineMessage(packetString)
|
||||
engine.parseEngineMessage(b64String)
|
||||
|
||||
waitForExpectations(timeout: 3, handler: nil)
|
||||
}
|
||||
|
||||
func testSettingExtraHeadersBeforeConnectSetsEngineExtraHeaders() {
|
||||
let newValue = ["hello": "world"]
|
||||
|
||||
manager.engine = engine
|
||||
manager.setTestStatus(.notConnected)
|
||||
manager.config = [.extraHeaders(["new": "value"])]
|
||||
manager.config.insert(.extraHeaders(newValue), replacing: true)
|
||||
|
||||
XCTAssertEqual(2, manager.config.count)
|
||||
XCTAssertEqual(manager.engine!.extraHeaders!, newValue)
|
||||
|
||||
for config in manager.config {
|
||||
switch config {
|
||||
case let .extraHeaders(headers):
|
||||
XCTAssertTrue(headers.keys.contains("hello"), "It should contain hello header key")
|
||||
XCTAssertFalse(headers.keys.contains("new"), "It should not contain old data")
|
||||
case .path:
|
||||
continue
|
||||
default:
|
||||
XCTFail("It should only have two configs")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func testSettingExtraHeadersAfterConnectDoesNotIgnoreChanges() {
|
||||
let newValue = ["hello": "world"]
|
||||
|
||||
manager.engine = engine
|
||||
manager.setTestStatus(.connected)
|
||||
engine.setConnected(true)
|
||||
manager.config = [.extraHeaders(["new": "value"])]
|
||||
manager.config.insert(.extraHeaders(["hello": "world"]), replacing: true)
|
||||
|
||||
XCTAssertEqual(2, manager.config.count)
|
||||
XCTAssertEqual(manager.engine!.extraHeaders!, newValue)
|
||||
}
|
||||
|
||||
func testSettingPathAfterConnectDoesNotIgnoreChanges() {
|
||||
let newValue = "/newpath/"
|
||||
|
||||
manager.engine = engine
|
||||
manager.setTestStatus(.connected)
|
||||
engine.setConnected(true)
|
||||
manager.config.insert(.path(newValue))
|
||||
|
||||
XCTAssertEqual(1, manager.config.count)
|
||||
XCTAssertEqual(manager.engine!.socketPath, newValue)
|
||||
}
|
||||
|
||||
func testSettingCompressAfterConnectDoesNotIgnoreChanges() {
|
||||
manager.engine = engine
|
||||
manager.setTestStatus(.connected)
|
||||
engine.setConnected(true)
|
||||
manager.config.insert(.compress)
|
||||
|
||||
XCTAssertEqual(2, manager.config.count)
|
||||
XCTAssertTrue(manager.engine!.compress)
|
||||
}
|
||||
|
||||
func testSettingForcePollingAfterConnectDoesNotIgnoreChanges() {
|
||||
manager.engine = engine
|
||||
manager.setTestStatus(.connected)
|
||||
engine.setConnected(true)
|
||||
manager.config.insert(.forcePolling(true))
|
||||
|
||||
XCTAssertEqual(2, manager.config.count)
|
||||
XCTAssertTrue(manager.engine!.forcePolling)
|
||||
}
|
||||
|
||||
func testSettingForceWebSocketsAfterConnectDoesNotIgnoreChanges() {
|
||||
manager.engine = engine
|
||||
manager.setTestStatus(.connected)
|
||||
engine.setConnected(true)
|
||||
manager.config.insert(.forceWebsockets(true))
|
||||
|
||||
XCTAssertEqual(2, manager.config.count)
|
||||
XCTAssertTrue(manager.engine!.forceWebsockets)
|
||||
}
|
||||
|
||||
func testChangingEngineHeadersAfterInit() {
|
||||
engine.extraHeaders = ["Hello": "World"]
|
||||
|
||||
let req = engine.createRequestForPostWithPostWait()
|
||||
|
||||
XCTAssertEqual("World", req.allHTTPHeaderFields?["Hello"])
|
||||
}
|
||||
|
||||
var manager: SocketManager!
|
||||
var socket: SocketIOClient!
|
||||
var engine: SocketEngine!
|
||||
|
||||
override func setUp() {
|
||||
super.setUp()
|
||||
|
||||
manager = SocketManager(socketURL: URL(string: "http://localhost")!)
|
||||
socket = manager.defaultSocket
|
||||
engine = SocketEngine(client: manager, url: URL(string: "http://localhost")!, options: nil)
|
||||
|
||||
socket.setTestable()
|
||||
}
|
||||
}
|
||||
46
Tests/TestSocketIO/SocketIOClientConfigurationTest.swift
Normal file
46
Tests/TestSocketIO/SocketIOClientConfigurationTest.swift
Normal file
@ -0,0 +1,46 @@
|
||||
//
|
||||
// TestSocketIOClientConfiguration.swift
|
||||
// Socket.IO-Client-Swift
|
||||
//
|
||||
// Created by Erik Little on 8/13/16.
|
||||
//
|
||||
//
|
||||
|
||||
import XCTest
|
||||
import SocketIO
|
||||
|
||||
class TestSocketIOClientConfiguration : XCTestCase {
|
||||
func testReplaceSameOption() {
|
||||
config.insert(.log(true))
|
||||
|
||||
XCTAssertEqual(config.count, 2)
|
||||
|
||||
switch config[0] {
|
||||
case let .log(log):
|
||||
XCTAssertTrue(log)
|
||||
default:
|
||||
XCTFail()
|
||||
}
|
||||
}
|
||||
|
||||
func testIgnoreIfExisting() {
|
||||
config.insert(.forceNew(false), replacing: false)
|
||||
|
||||
XCTAssertEqual(config.count, 2)
|
||||
|
||||
switch config[1] {
|
||||
case let .forceNew(new):
|
||||
XCTAssertTrue(new)
|
||||
default:
|
||||
XCTFail()
|
||||
}
|
||||
}
|
||||
|
||||
var config = [] as SocketIOClientConfiguration
|
||||
|
||||
override func setUp() {
|
||||
config = [.log(false), .forceNew(true)]
|
||||
|
||||
super.setUp()
|
||||
}
|
||||
}
|
||||
247
Tests/TestSocketIO/SocketMangerTest.swift
Normal file
247
Tests/TestSocketIO/SocketMangerTest.swift
Normal file
@ -0,0 +1,247 @@
|
||||
//
|
||||
// Created by Erik Little on 10/21/17.
|
||||
//
|
||||
|
||||
import Dispatch
|
||||
import Foundation
|
||||
@testable import SocketIO
|
||||
import XCTest
|
||||
|
||||
class SocketMangerTest : XCTestCase {
|
||||
func testManagerProperties() {
|
||||
XCTAssertNotNil(manager.defaultSocket)
|
||||
XCTAssertNil(manager.engine)
|
||||
XCTAssertFalse(manager.forceNew)
|
||||
XCTAssertEqual(manager.handleQueue, DispatchQueue.main)
|
||||
XCTAssertTrue(manager.reconnects)
|
||||
XCTAssertEqual(manager.reconnectWait, 10)
|
||||
XCTAssertEqual(manager.reconnectWaitMax, 30)
|
||||
XCTAssertEqual(manager.randomizationFactor, 0.5)
|
||||
XCTAssertEqual(manager.status, .notConnected)
|
||||
}
|
||||
|
||||
func testSettingConfig() {
|
||||
let manager = SocketManager(socketURL: URL(string: "https://example.com/")!)
|
||||
|
||||
XCTAssertEqual(manager.config.first!, .secure(true))
|
||||
|
||||
manager.config = []
|
||||
|
||||
XCTAssertEqual(manager.config.first!, .secure(true))
|
||||
}
|
||||
|
||||
func testBackoffIntervalCalulation() {
|
||||
XCTAssertLessThanOrEqual(manager.reconnectInterval(attempts: -1), Double(manager.reconnectWaitMax))
|
||||
XCTAssertLessThanOrEqual(manager.reconnectInterval(attempts: 0), 15)
|
||||
XCTAssertLessThanOrEqual(manager.reconnectInterval(attempts: 1), 22.5)
|
||||
XCTAssertLessThanOrEqual(manager.reconnectInterval(attempts: 2), 33.75)
|
||||
XCTAssertLessThanOrEqual(manager.reconnectInterval(attempts: 50), Double(manager.reconnectWaitMax))
|
||||
XCTAssertLessThanOrEqual(manager.reconnectInterval(attempts: 10000), Double(manager.reconnectWaitMax))
|
||||
|
||||
XCTAssertGreaterThanOrEqual(manager.reconnectInterval(attempts: -1), Double(manager.reconnectWait))
|
||||
XCTAssertGreaterThanOrEqual(manager.reconnectInterval(attempts: 0), Double(manager.reconnectWait))
|
||||
XCTAssertGreaterThanOrEqual(manager.reconnectInterval(attempts: 1), 15)
|
||||
XCTAssertGreaterThanOrEqual(manager.reconnectInterval(attempts: 2), 22.5)
|
||||
XCTAssertGreaterThanOrEqual(manager.reconnectInterval(attempts: 10000), Double(manager.reconnectWait))
|
||||
}
|
||||
|
||||
func testManagerCallsConnect() {
|
||||
setUpSockets()
|
||||
|
||||
socket.expectations[ManagerExpectation.didConnectCalled] = expectation(description: "The manager should call connect on the default socket")
|
||||
socket2.expectations[ManagerExpectation.didConnectCalled] = expectation(description: "The manager should call connect on the socket")
|
||||
|
||||
socket.connect()
|
||||
socket2.connect()
|
||||
|
||||
manager.fakeConnecting()
|
||||
manager.fakeConnecting(toNamespace: "/swift")
|
||||
|
||||
waitForExpectations(timeout: 0.3)
|
||||
}
|
||||
|
||||
func testManagerDoesNotCallConnectWhenConnectingWithLessThanOneReconnect() {
|
||||
setUpSockets()
|
||||
|
||||
let expect = expectation(description: "The manager should not call connect on the engine")
|
||||
expect.isInverted = true
|
||||
|
||||
let engine = TestEngine(client: manager, url: manager.socketURL, options: nil)
|
||||
|
||||
engine.onConnect = {
|
||||
expect.fulfill()
|
||||
}
|
||||
manager.setTestStatus(.connecting)
|
||||
manager.setCurrentReconnect(currentReconnect: 0)
|
||||
manager.engine = engine
|
||||
|
||||
manager.connect()
|
||||
|
||||
waitForExpectations(timeout: 0.3)
|
||||
}
|
||||
|
||||
func testManagerCallConnectWhenConnectingAndMoreThanOneReconnect() {
|
||||
setUpSockets()
|
||||
|
||||
let expect = expectation(description: "The manager should call connect on the engine")
|
||||
let engine = TestEngine(client: manager, url: manager.socketURL, options: nil)
|
||||
|
||||
engine.onConnect = {
|
||||
expect.fulfill()
|
||||
}
|
||||
manager.setTestStatus(.connecting)
|
||||
manager.setCurrentReconnect(currentReconnect: 1)
|
||||
manager.engine = engine
|
||||
|
||||
manager.connect()
|
||||
|
||||
waitForExpectations(timeout: 0.8)
|
||||
}
|
||||
|
||||
func testManagerCallsDisconnect() {
|
||||
setUpSockets()
|
||||
|
||||
socket.expectations[ManagerExpectation.didDisconnectCalled] = expectation(description: "The manager should call disconnect on the default socket")
|
||||
socket2.expectations[ManagerExpectation.didDisconnectCalled] = expectation(description: "The manager should call disconnect on the socket")
|
||||
|
||||
socket2.on(clientEvent: .connect) {data, ack in
|
||||
self.manager.disconnect()
|
||||
self.manager.fakeDisconnecting()
|
||||
}
|
||||
|
||||
socket.connect()
|
||||
socket2.connect()
|
||||
|
||||
manager.fakeConnecting()
|
||||
manager.fakeConnecting(toNamespace: "/swift")
|
||||
|
||||
waitForExpectations(timeout: 0.3)
|
||||
}
|
||||
|
||||
// func testManagerEmitAll() {
|
||||
// setUpSockets()
|
||||
//
|
||||
// socket.expectations[ManagerExpectation.emitAllEventCalled] = expectation(description: "The manager should emit an event to the default socket")
|
||||
// socket2.expectations[ManagerExpectation.emitAllEventCalled] = expectation(description: "The manager should emit an event to the socket")
|
||||
//
|
||||
// socket2.on(clientEvent: .connect) {data, ack in
|
||||
// print("connect")
|
||||
// self.manager.emitAll("event", "testing")
|
||||
// }
|
||||
//
|
||||
// socket.connect()
|
||||
// socket2.connect()
|
||||
//
|
||||
// manager.fakeConnecting(toNamespace: "/swift")
|
||||
//
|
||||
// waitForExpectations(timeout: 0.3)
|
||||
// }
|
||||
|
||||
func testManagerSetsConfigs() {
|
||||
let queue = DispatchQueue(label: "testQueue")
|
||||
|
||||
manager = TestManager(socketURL: URL(string: "http://localhost/")!, config: [
|
||||
.handleQueue(queue),
|
||||
.forceNew(true),
|
||||
.reconnects(false),
|
||||
.reconnectWait(5),
|
||||
.reconnectWaitMax(5),
|
||||
.randomizationFactor(0.7),
|
||||
.reconnectAttempts(5)
|
||||
])
|
||||
|
||||
XCTAssertEqual(manager.handleQueue, queue)
|
||||
XCTAssertTrue(manager.forceNew)
|
||||
XCTAssertFalse(manager.reconnects)
|
||||
XCTAssertEqual(manager.reconnectWait, 5)
|
||||
XCTAssertEqual(manager.reconnectWaitMax, 5)
|
||||
XCTAssertEqual(manager.randomizationFactor, 0.7)
|
||||
XCTAssertEqual(manager.reconnectAttempts, 5)
|
||||
}
|
||||
|
||||
func testManagerRemovesSocket() {
|
||||
setUpSockets()
|
||||
|
||||
manager.removeSocket(socket)
|
||||
|
||||
XCTAssertNil(manager.nsps[socket.nsp])
|
||||
}
|
||||
|
||||
private func setUpSockets() {
|
||||
socket = manager.testSocket(forNamespace: "/")
|
||||
socket2 = manager.testSocket(forNamespace: "/swift")
|
||||
}
|
||||
|
||||
private var manager: TestManager!
|
||||
private var socket: TestSocket!
|
||||
private var socket2: TestSocket!
|
||||
|
||||
override func setUp() {
|
||||
super.setUp()
|
||||
|
||||
manager = TestManager(socketURL: URL(string: "http://localhost/")!, config: [.log(false)])
|
||||
socket = nil
|
||||
socket2 = nil
|
||||
}
|
||||
}
|
||||
|
||||
public enum ManagerExpectation: String {
|
||||
case didConnectCalled
|
||||
case didDisconnectCalled
|
||||
case emitAllEventCalled
|
||||
}
|
||||
|
||||
public class TestManager: SocketManager {
|
||||
public func setCurrentReconnect(currentReconnect: Int) {
|
||||
self.currentReconnectAttempt = currentReconnect
|
||||
}
|
||||
|
||||
public override func disconnect() {
|
||||
setTestStatus(.disconnected)
|
||||
}
|
||||
|
||||
public func testSocket(forNamespace nsp: String) -> TestSocket {
|
||||
return socket(forNamespace: nsp) as! TestSocket
|
||||
}
|
||||
|
||||
public func fakeDisconnecting() {
|
||||
engineDidClose(reason: "")
|
||||
}
|
||||
|
||||
public func fakeConnecting(toNamespace nsp: String = "/") {
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
|
||||
// Fake connecting
|
||||
self.parseEngineMessage("0\(nsp)")
|
||||
}
|
||||
}
|
||||
|
||||
public override func socket(forNamespace nsp: String) -> SocketIOClient {
|
||||
// set socket to our test socket, the superclass method will get this from nsps
|
||||
nsps[nsp] = TestSocket(manager: self, nsp: nsp)
|
||||
|
||||
return super.socket(forNamespace: nsp)
|
||||
}
|
||||
}
|
||||
|
||||
public class TestSocket: SocketIOClient {
|
||||
public var expectations = [ManagerExpectation: XCTestExpectation]()
|
||||
|
||||
public override func didConnect(toNamespace nsp: String, payload: [String: Any]?) {
|
||||
expectations[ManagerExpectation.didConnectCalled]?.fulfill()
|
||||
expectations[ManagerExpectation.didConnectCalled] = nil
|
||||
|
||||
super.didConnect(toNamespace: nsp, payload: payload)
|
||||
}
|
||||
|
||||
public override func didDisconnect(reason: String) {
|
||||
expectations[ManagerExpectation.didDisconnectCalled]?.fulfill()
|
||||
expectations[ManagerExpectation.didDisconnectCalled] = nil
|
||||
|
||||
super.didDisconnect(reason: reason)
|
||||
}
|
||||
|
||||
public override func emit(_ event: String, _ items: SocketData..., completion: (() -> ())? = nil) {
|
||||
expectations[ManagerExpectation.emitAllEventCalled]?.fulfill()
|
||||
expectations[ManagerExpectation.emitAllEventCalled] = nil
|
||||
}
|
||||
}
|
||||
206
Tests/TestSocketIO/SocketNamespacePacketTest.swift
Normal file
206
Tests/TestSocketIO/SocketNamespacePacketTest.swift
Normal file
@ -0,0 +1,206 @@
|
||||
//
|
||||
// SocketNamespacePacketTest.swift
|
||||
// Socket.IO-Client-Swift
|
||||
//
|
||||
// Created by Erik Little on 10/11/15.
|
||||
//
|
||||
//
|
||||
|
||||
import XCTest
|
||||
@testable import SocketIO
|
||||
|
||||
class SocketNamespacePacketTest : XCTestCase {
|
||||
func testEmptyEmit() {
|
||||
let sendData: [Any] = ["test"]
|
||||
let packet = SocketPacket.packetFromEmit(sendData, id: -1, nsp: "/swift", ack: false)
|
||||
let parsed = parser.parseSocketMessage(packet.packetString)!
|
||||
|
||||
XCTAssertEqual(parsed.type, .event)
|
||||
XCTAssertEqual(parsed.nsp, "/swift")
|
||||
XCTAssertTrue(compareAnyArray(input: parsed.data, expected: sendData))
|
||||
}
|
||||
|
||||
func testNullEmit() {
|
||||
let sendData: [Any] = ["test", NSNull()]
|
||||
let packet = SocketPacket.packetFromEmit(sendData, id: -1, nsp: "/swift", ack: false)
|
||||
let parsed = parser.parseSocketMessage(packet.packetString)!
|
||||
|
||||
XCTAssertEqual(parsed.type, .event)
|
||||
XCTAssertEqual(parsed.nsp, "/swift")
|
||||
XCTAssertTrue(compareAnyArray(input: parsed.data, expected: sendData))
|
||||
}
|
||||
|
||||
func testStringEmit() {
|
||||
let sendData: [Any] = ["test", "foo bar"]
|
||||
let packet = SocketPacket.packetFromEmit(sendData, id: -1, nsp: "/swift", ack: false)
|
||||
let parsed = parser.parseSocketMessage(packet.packetString)!
|
||||
|
||||
XCTAssertEqual(parsed.type, .event)
|
||||
XCTAssertEqual(parsed.nsp, "/swift")
|
||||
XCTAssertTrue(compareAnyArray(input: parsed.data, expected: sendData))
|
||||
}
|
||||
|
||||
func testJSONEmit() {
|
||||
let sendData: [Any] = ["test", ["foobar": true, "hello": 1, "test": "hello", "null": NSNull()] as NSDictionary]
|
||||
let packet = SocketPacket.packetFromEmit(sendData, id: -1, nsp: "/swift", ack: false)
|
||||
let parsed = parser.parseSocketMessage(packet.packetString)!
|
||||
|
||||
XCTAssertEqual(parsed.type, .event)
|
||||
XCTAssertEqual(parsed.nsp, "/swift")
|
||||
XCTAssertTrue(compareAnyArray(input: parsed.data, expected: sendData))
|
||||
}
|
||||
|
||||
func testArrayEmit() {
|
||||
let sendData: [Any] = ["test", ["hello", 1, ["test": "test"], true]]
|
||||
let packet = SocketPacket.packetFromEmit(sendData, id: -1, nsp: "/swift", ack: false)
|
||||
let parsed = parser.parseSocketMessage(packet.packetString)!
|
||||
|
||||
XCTAssertEqual(parsed.type, .event)
|
||||
XCTAssertEqual(parsed.nsp, "/swift")
|
||||
XCTAssertTrue(compareAnyArray(input: parsed.data, expected: sendData))
|
||||
}
|
||||
|
||||
func testBinaryEmit() {
|
||||
let sendData: [Any] = ["test", data]
|
||||
let packet = SocketPacket.packetFromEmit(sendData, id: -1, nsp: "/swift", ack: false)
|
||||
let parsed = parser.parseSocketMessage(packet.packetString)!
|
||||
|
||||
XCTAssertEqual(parsed.type, .binaryEvent)
|
||||
XCTAssertEqual(parsed.nsp, "/swift")
|
||||
XCTAssertEqual(packet.binary, [data])
|
||||
XCTAssertTrue(compareAnyArray(input: parsed.data, expected: [
|
||||
"test",
|
||||
["_placeholder": true, "num": 0]
|
||||
]))
|
||||
}
|
||||
|
||||
func testMultipleBinaryEmit() {
|
||||
let sendData: [Any] = ["test", ["data1": data, "data2": data2] as NSDictionary]
|
||||
let packet = SocketPacket.packetFromEmit(sendData, id: -1, nsp: "/swift", ack: false)
|
||||
let parsed = parser.parseSocketMessage(packet.packetString)!
|
||||
|
||||
XCTAssertEqual(parsed.type, .binaryEvent)
|
||||
XCTAssertEqual(parsed.nsp, "/swift")
|
||||
|
||||
let binaryObj = parsed.data[1] as! [String: Any]
|
||||
let data1Loc = (binaryObj["data1"] as! [String: Any])["num"] as! Int
|
||||
let data2Loc = (binaryObj["data2"] as! [String: Any])["num"] as! Int
|
||||
|
||||
XCTAssertEqual(packet.binary[data1Loc], data)
|
||||
XCTAssertEqual(packet.binary[data2Loc], data2)
|
||||
}
|
||||
|
||||
func testEmitWithAck() {
|
||||
let sendData = ["test"]
|
||||
let packet = SocketPacket.packetFromEmit(sendData, id: 0, nsp: "/swift", ack: false)
|
||||
let parsed = parser.parseSocketMessage(packet.packetString)!
|
||||
|
||||
XCTAssertEqual(parsed.type, .event)
|
||||
XCTAssertEqual(parsed.nsp, "/swift")
|
||||
XCTAssertEqual(parsed.id, 0)
|
||||
XCTAssertTrue(compareAnyArray(input: parsed.data, expected: sendData))
|
||||
}
|
||||
|
||||
func testEmitDataWithAck() {
|
||||
let sendData: [Any] = ["test", data]
|
||||
let packet = SocketPacket.packetFromEmit(sendData, id: 0, nsp: "/swift", ack: false)
|
||||
let parsed = parser.parseSocketMessage(packet.packetString)!
|
||||
|
||||
XCTAssertEqual(parsed.type, .binaryEvent)
|
||||
XCTAssertEqual(parsed.nsp, "/swift")
|
||||
XCTAssertEqual(parsed.id, 0)
|
||||
XCTAssertTrue(compareAnyArray(input: parsed.data, expected: [
|
||||
"test",
|
||||
["_placeholder": true, "num": 0]
|
||||
]))
|
||||
}
|
||||
|
||||
// Acks
|
||||
func testEmptyAck() {
|
||||
let packet = SocketPacket.packetFromEmit([], id: 0, nsp: "/swift", ack: true)
|
||||
let parsed = parser.parseSocketMessage(packet.packetString)!
|
||||
|
||||
XCTAssertEqual(parsed.type, .ack)
|
||||
XCTAssertEqual(parsed.nsp, "/swift")
|
||||
XCTAssertEqual(parsed.id, 0)
|
||||
}
|
||||
|
||||
func testNullAck() {
|
||||
let sendData = [NSNull()]
|
||||
let packet = SocketPacket.packetFromEmit(sendData, id: 0, nsp: "/swift", ack: true)
|
||||
let parsed = parser.parseSocketMessage(packet.packetString)!
|
||||
|
||||
XCTAssertEqual(parsed.type, .ack)
|
||||
XCTAssertEqual(parsed.nsp, "/swift")
|
||||
XCTAssertEqual(parsed.id, 0)
|
||||
XCTAssertTrue(compareAnyArray(input: parsed.data, expected: sendData))
|
||||
}
|
||||
|
||||
func testStringAck() {
|
||||
let sendData = ["test"]
|
||||
let packet = SocketPacket.packetFromEmit(sendData, id: 0, nsp: "/swift", ack: true)
|
||||
let parsed = parser.parseSocketMessage(packet.packetString)!
|
||||
|
||||
XCTAssertEqual(parsed.type, .ack)
|
||||
XCTAssertEqual(parsed.nsp, "/swift")
|
||||
XCTAssertEqual(parsed.id, 0)
|
||||
XCTAssertTrue(compareAnyArray(input: parsed.data, expected: sendData))
|
||||
}
|
||||
|
||||
func testJSONAck() {
|
||||
let sendData = [["foobar": true, "hello": 1, "test": "hello", "null": NSNull()]]
|
||||
let packet = SocketPacket.packetFromEmit(sendData, id: 0, nsp: "/swift", ack: true)
|
||||
let parsed = parser.parseSocketMessage(packet.packetString)!
|
||||
|
||||
XCTAssertEqual(parsed.type, .ack)
|
||||
XCTAssertEqual(parsed.nsp, "/swift")
|
||||
XCTAssertEqual(parsed.id, 0)
|
||||
XCTAssertTrue(compareAnyArray(input: parsed.data, expected: sendData))
|
||||
}
|
||||
|
||||
func testBinaryAck() {
|
||||
let sendData = [data]
|
||||
let packet = SocketPacket.packetFromEmit(sendData, id: 0, nsp: "/swift", ack: true)
|
||||
let parsed = parser.parseSocketMessage(packet.packetString)!
|
||||
|
||||
XCTAssertEqual(parsed.type, .binaryAck)
|
||||
XCTAssertEqual(parsed.nsp, "/swift")
|
||||
XCTAssertEqual(parsed.id, 0)
|
||||
XCTAssertTrue(compareAnyArray(input: parsed.data, expected: [
|
||||
["_placeholder": true, "num": 0]
|
||||
]))
|
||||
}
|
||||
|
||||
func testMultipleBinaryAck() {
|
||||
let sendData = [["data1": data, "data2": data2]]
|
||||
let packet = SocketPacket.packetFromEmit(sendData, id: 0, nsp: "/swift", ack: true)
|
||||
let parsed = parser.parseSocketMessage(packet.packetString)!
|
||||
|
||||
XCTAssertEqual(parsed.type, .binaryAck)
|
||||
XCTAssertEqual(parsed.nsp, "/swift")
|
||||
XCTAssertEqual(parsed.id, 0)
|
||||
|
||||
let binaryObj = parsed.data[0] as! [String: Any]
|
||||
let data1Loc = (binaryObj["data1"] as! [String: Any])["num"] as! Int
|
||||
let data2Loc = (binaryObj["data2"] as! [String: Any])["num"] as! Int
|
||||
|
||||
XCTAssertEqual(packet.binary[data1Loc], data)
|
||||
XCTAssertEqual(packet.binary[data2Loc], data2)
|
||||
}
|
||||
|
||||
let data = "test".data(using: String.Encoding.utf8)!
|
||||
let data2 = "test2".data(using: String.Encoding.utf8)!
|
||||
var parser: SocketParsable!
|
||||
|
||||
private func compareAnyArray(input: [Any], expected: [Any]) -> Bool {
|
||||
guard input.count == expected.count else { return false }
|
||||
|
||||
return (input as NSArray).isEqual(to: expected)
|
||||
}
|
||||
|
||||
override func setUp() {
|
||||
super.setUp()
|
||||
|
||||
parser = SocketManager(socketURL: URL(string: "http://localhost")!)
|
||||
}
|
||||
}
|
||||
@ -7,27 +7,9 @@
|
||||
//
|
||||
|
||||
import XCTest
|
||||
@testable import SocketIOClientSwift
|
||||
@testable import SocketIO
|
||||
|
||||
class SocketParserTest: XCTestCase {
|
||||
let testSocket = SocketIOClient(socketURL: NSURL())
|
||||
|
||||
//Format key: message; namespace-data-binary-id
|
||||
static let packetTypes: Dictionary<String, (String, [AnyObject], [NSData], Int)> = [
|
||||
"0": ("/", [], [], -1), "1": ("/", [], [], -1),
|
||||
"25[\"test\"]": ("/", ["test"], [], 5),
|
||||
"2[\"test\",\"~~0\"]": ("/", ["test", "~~0"], [], -1),
|
||||
"2/swift,[\"testArrayEmitReturn\",[\"test3\",\"test4\"]]": ("/swift", ["testArrayEmitReturn", ["test3", "test4"]], [], -1),
|
||||
"51-/swift,[\"testMultipleItemsWithBufferEmitReturn\",[1,2],{\"test\":\"bob\"},25,\"polo\",{\"_placeholder\":true,\"num\":0}]": ("/swift", ["testMultipleItemsWithBufferEmitReturn", [1, 2], ["test": "bob"], 25, "polo", "~~0"], [], -1),
|
||||
"3/swift,0[[\"test3\",\"test4\"]]": ("/swift", [["test3", "test4"]], [], 0),
|
||||
"61-/swift,19[[1,2],{\"test\":\"bob\"},25,\"polo\",{\"_placeholder\":true,\"num\":0}]": ("/swift", [ [1, 2], ["test": "bob"], 25, "polo", "~~0"], [], 19),
|
||||
"4/swift,": ("/swift", [], [], -1),
|
||||
"0/swift": ("/swift", [], [], -1),
|
||||
"1/swift": ("/swift", [], [], -1),
|
||||
"4\"ERROR\"": ("/", ["ERROR"], [], -1),
|
||||
"4{\"test\":2}": ("/", [["test": 2]], [], -1),
|
||||
"41": ("/", [1], [], -1)]
|
||||
|
||||
func testDisconnect() {
|
||||
let message = "1"
|
||||
validateParseResult(message)
|
||||
@ -37,106 +19,129 @@ class SocketParserTest: XCTestCase {
|
||||
let message = "0"
|
||||
validateParseResult(message)
|
||||
}
|
||||
|
||||
|
||||
func testDisconnectNameSpace() {
|
||||
let message = "1/swift"
|
||||
validateParseResult(message)
|
||||
}
|
||||
|
||||
|
||||
func testConnecttNameSpace() {
|
||||
let message = "0/swift"
|
||||
validateParseResult(message)
|
||||
}
|
||||
|
||||
|
||||
func testIdEvent() {
|
||||
let message = "25[\"test\"]"
|
||||
validateParseResult(message)
|
||||
}
|
||||
|
||||
|
||||
func testBinaryPlaceholderAsString() {
|
||||
let message = "2[\"test\",\"~~0\"]"
|
||||
validateParseResult(message)
|
||||
}
|
||||
|
||||
|
||||
func testNameSpaceArrayParse() {
|
||||
let message = "2/swift,[\"testArrayEmitReturn\",[\"test3\",\"test4\"]]"
|
||||
validateParseResult(message)
|
||||
}
|
||||
|
||||
|
||||
func testNameSpaceArrayAckParse() {
|
||||
let message = "3/swift,0[[\"test3\",\"test4\"]]"
|
||||
validateParseResult(message)
|
||||
}
|
||||
|
||||
|
||||
func testNameSpaceBinaryEventParse() {
|
||||
let message = "51-/swift,[\"testMultipleItemsWithBufferEmitReturn\",[1,2],{\"test\":\"bob\"},25,\"polo\",{\"_placeholder\":true,\"num\":0}]"
|
||||
validateParseResult(message)
|
||||
}
|
||||
|
||||
|
||||
func testNameSpaceBinaryAckParse() {
|
||||
let message = "61-/swift,19[[1,2],{\"test\":\"bob\"},25,\"polo\",{\"_placeholder\":true,\"num\":0}]"
|
||||
validateParseResult(message)
|
||||
}
|
||||
|
||||
|
||||
func testNamespaceErrorParse() {
|
||||
let message = "4/swift,"
|
||||
validateParseResult(message)
|
||||
}
|
||||
|
||||
|
||||
func testErrorTypeString() {
|
||||
let message = "4\"ERROR\""
|
||||
validateParseResult(message)
|
||||
}
|
||||
|
||||
|
||||
func testErrorTypeDictionary() {
|
||||
let message = "4{\"test\":2}"
|
||||
validateParseResult(message)
|
||||
}
|
||||
|
||||
|
||||
func testErrorTypeInt() {
|
||||
let message = "41"
|
||||
validateParseResult(message)
|
||||
}
|
||||
|
||||
|
||||
func testErrorTypeArray() {
|
||||
let message = "4[1, \"hello\"]"
|
||||
validateParseResult(message)
|
||||
}
|
||||
|
||||
func testInvalidInput() {
|
||||
let message = "8"
|
||||
switch testSocket.parseString(message) {
|
||||
case .Left(_):
|
||||
return
|
||||
case .Right(_):
|
||||
XCTFail("Created packet when shouldn't have")
|
||||
do {
|
||||
let _ = try testManager.parseString(message)
|
||||
XCTFail()
|
||||
} catch {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
func testGenericParser() {
|
||||
var parser = SocketStringReader(message: "61-/swift,")
|
||||
XCTAssertEqual(parser.read(1), "6")
|
||||
XCTAssertEqual(parser.read(count: 1), "6")
|
||||
XCTAssertEqual(parser.currentCharacter, "1")
|
||||
XCTAssertEqual(parser.readUntilStringOccurence("-"), "1")
|
||||
XCTAssertEqual(parser.readUntilOccurence(of: "-"), "1")
|
||||
XCTAssertEqual(parser.currentCharacter, "/")
|
||||
}
|
||||
|
||||
func validateParseResult(message: String) {
|
||||
|
||||
func validateParseResult(_ message: String) {
|
||||
let validValues = SocketParserTest.packetTypes[message]!
|
||||
let packet = testSocket.parseString(message)
|
||||
let type = message.substringWithRange(Range<String.Index>(message.startIndex..<message.startIndex.advancedBy(1)))
|
||||
if case let .Right(packet) = packet {
|
||||
XCTAssertEqual(packet.type, SocketPacket.PacketType(rawValue: Int(type) ?? -1)!)
|
||||
XCTAssertEqual(packet.nsp, validValues.0)
|
||||
XCTAssertTrue((packet.data as NSArray).isEqualToArray(validValues.1))
|
||||
XCTAssertTrue((packet.binary as NSArray).isEqualToArray(validValues.2))
|
||||
XCTAssertEqual(packet.id, validValues.3)
|
||||
} else {
|
||||
XCTFail()
|
||||
}
|
||||
let packet = try! testManager.parseString(message)
|
||||
let type = String(message.prefix(1))
|
||||
|
||||
XCTAssertEqual(packet.type, SocketPacket.PacketType(rawValue: Int(type) ?? -1)!)
|
||||
XCTAssertEqual(packet.nsp, validValues.0)
|
||||
XCTAssertTrue((packet.data as NSArray).isEqual(to: validValues.1), "\(packet.data)")
|
||||
XCTAssertTrue((packet.binary as NSArray).isEqual(to: validValues.2), "\(packet.binary)")
|
||||
XCTAssertEqual(packet.id, validValues.3)
|
||||
}
|
||||
|
||||
|
||||
func testParsePerformance() {
|
||||
let keys = Array(SocketParserTest.packetTypes.keys)
|
||||
measureBlock({
|
||||
for item in keys.enumerate() {
|
||||
self.testSocket.parseString(item.element)
|
||||
measure {
|
||||
for item in keys.enumerated() {
|
||||
_ = try! self.testManager.parseString(item.element)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
let testManager = SocketManager(socketURL: URL(string: "http://localhost/")!)
|
||||
|
||||
//Format key: message; namespace-data-binary-id
|
||||
static let packetTypes: [String: (String, [Any], [Data], Int)] = [
|
||||
"0": ("/", [], [], -1), "1": ("/", [], [], -1),
|
||||
"25[\"test\"]": ("/", ["test"], [], 5),
|
||||
"2[\"test\",\"~~0\"]": ("/", ["test", "~~0"], [], -1),
|
||||
"2/swift,[\"testArrayEmitReturn\",[\"test3\",\"test4\"]]": ("/swift", ["testArrayEmitReturn", ["test3", "test4"] as NSArray], [], -1),
|
||||
"51-/swift,[\"testMultipleItemsWithBufferEmitReturn\",[1,2],{\"test\":\"bob\"},25,\"polo\",{\"_placeholder\":true,\"num\":0}]": ("/swift", ["testMultipleItemsWithBufferEmitReturn", [1, 2] as NSArray, ["test": "bob"] as NSDictionary, 25, "polo", ["_placeholder": true, "num": 0] as NSDictionary], [], -1),
|
||||
"3/swift,0[[\"test3\",\"test4\"]]": ("/swift", [["test3", "test4"] as NSArray], [], 0),
|
||||
"61-/swift,19[[1,2],{\"test\":\"bob\"},25,\"polo\",{\"_placeholder\":true,\"num\":0}]":
|
||||
("/swift", [ [1, 2] as NSArray, ["test": "bob"] as NSDictionary, 25, "polo", ["_placeholder": true, "num": 0] as NSDictionary], [], 19),
|
||||
"4/swift,": ("/swift", [], [], -1),
|
||||
"0/swift": ("/swift", [], [], -1),
|
||||
"1/swift": ("/swift", [], [], -1),
|
||||
"4\"ERROR\"": ("/", ["ERROR"], [], -1),
|
||||
"4{\"test\":2}": ("/", [["test": 2]], [], -1),
|
||||
"41": ("/", [1], [], -1),
|
||||
"4[1, \"hello\"]": ("/", [1, "hello"], [], -1)
|
||||
]
|
||||
}
|
||||
507
Tests/TestSocketIO/SocketSideEffectTest.swift
Normal file
507
Tests/TestSocketIO/SocketSideEffectTest.swift
Normal file
@ -0,0 +1,507 @@
|
||||
//
|
||||
// SocketSideEffectTest.swift
|
||||
// Socket.IO-Client-Swift
|
||||
//
|
||||
// Created by Erik Little on 10/11/15.
|
||||
//
|
||||
//
|
||||
|
||||
import XCTest
|
||||
@testable import SocketIO
|
||||
import Starscream
|
||||
|
||||
class SocketSideEffectTest: XCTestCase {
|
||||
func testInitialCurrentAck() {
|
||||
XCTAssertEqual(socket.currentAck, -1)
|
||||
}
|
||||
|
||||
func testFirstAck() {
|
||||
socket.emitWithAck("test").timingOut(after: 0) {data in}
|
||||
XCTAssertEqual(socket.currentAck, 0)
|
||||
}
|
||||
|
||||
func testSecondAck() {
|
||||
socket.emitWithAck("test").timingOut(after: 0) {data in}
|
||||
socket.emitWithAck("test").timingOut(after: 0) {data in}
|
||||
|
||||
XCTAssertEqual(socket.currentAck, 1)
|
||||
}
|
||||
|
||||
func testEmitCompletionSyntax() {
|
||||
socket.emit("test", completion: {})
|
||||
socket.emit("test", "thing", completion: {})
|
||||
}
|
||||
|
||||
func testHandleAck() {
|
||||
let expect = expectation(description: "handled ack")
|
||||
socket.emitWithAck("test").timingOut(after: 0) {data in
|
||||
XCTAssertEqual(data[0] as? String, "hello world")
|
||||
expect.fulfill()
|
||||
}
|
||||
|
||||
manager.parseEngineMessage("30[\"hello world\"]")
|
||||
waitForExpectations(timeout: 3, handler: nil)
|
||||
}
|
||||
|
||||
func testHandleAckWithAckEmit() {
|
||||
let expect = expectation(description: "handled ack")
|
||||
socket.emitWithAck("test").timingOut(after: 0) {data in
|
||||
XCTAssertEqual(data[0] as? String, "hello world")
|
||||
|
||||
self.socket.emitWithAck("test").timingOut(after: 0) {data in}
|
||||
expect.fulfill()
|
||||
}
|
||||
|
||||
manager.parseEngineMessage("30[\"hello world\"]")
|
||||
waitForExpectations(timeout: 3, handler: nil)
|
||||
}
|
||||
|
||||
func testHandleAck2() {
|
||||
let expect = expectation(description: "handled ack2")
|
||||
socket.emitWithAck("test").timingOut(after: 0) {data in
|
||||
XCTAssertTrue(data.count == 2, "Wrong number of ack items")
|
||||
expect.fulfill()
|
||||
}
|
||||
|
||||
manager.parseEngineMessage("61-0[{\"_placeholder\":true,\"num\":0},{\"test\":true}]")
|
||||
manager.parseEngineBinaryData(Data())
|
||||
waitForExpectations(timeout: 3, handler: nil)
|
||||
}
|
||||
|
||||
func testHandleEvent() {
|
||||
let expect = expectation(description: "handled event")
|
||||
socket.on("test") {data, ack in
|
||||
XCTAssertEqual(data[0] as? String, "hello world")
|
||||
expect.fulfill()
|
||||
}
|
||||
|
||||
manager.parseEngineMessage("2[\"test\",\"hello world\"]")
|
||||
waitForExpectations(timeout: 3, handler: nil)
|
||||
}
|
||||
|
||||
func testHandleStringEventWithQuotes() {
|
||||
let expect = expectation(description: "handled event")
|
||||
socket.on("test") {data, ack in
|
||||
XCTAssertEqual(data[0] as? String, "\"hello world\"")
|
||||
expect.fulfill()
|
||||
}
|
||||
|
||||
manager.parseEngineMessage("2[\"test\",\"\\\"hello world\\\"\"]")
|
||||
waitForExpectations(timeout: 3, handler: nil)
|
||||
}
|
||||
|
||||
func testHandleOnceEvent() {
|
||||
let expect = expectation(description: "handled event")
|
||||
socket.once("test") {data, ack in
|
||||
XCTAssertEqual(data[0] as? String, "hello world")
|
||||
XCTAssertEqual(self.socket.testHandlers.count, 0)
|
||||
expect.fulfill()
|
||||
}
|
||||
|
||||
manager.parseEngineMessage("2[\"test\",\"hello world\"]")
|
||||
waitForExpectations(timeout: 3, handler: nil)
|
||||
}
|
||||
|
||||
func testHandleOnceClientEvent() {
|
||||
let expect = expectation(description: "handled event")
|
||||
|
||||
socket.setTestStatus(.connecting)
|
||||
|
||||
socket.once(clientEvent: .connect) {data, ack in
|
||||
XCTAssertEqual(self.socket.testHandlers.count, 0)
|
||||
expect.fulfill()
|
||||
}
|
||||
|
||||
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 0.1) {
|
||||
// Fake connecting
|
||||
self.manager.parseEngineMessage("0/")
|
||||
}
|
||||
|
||||
waitForExpectations(timeout: 3, handler: nil)
|
||||
}
|
||||
|
||||
func testOffWithEvent() {
|
||||
socket.on("test") {data, ack in }
|
||||
socket.on("test") {data, ack in }
|
||||
XCTAssertEqual(socket.testHandlers.count, 2)
|
||||
socket.off("test")
|
||||
XCTAssertEqual(socket.testHandlers.count, 0)
|
||||
}
|
||||
|
||||
func testOffClientEvent() {
|
||||
socket.on(clientEvent: .connect) {data, ack in }
|
||||
socket.on(clientEvent: .disconnect) {data, ack in }
|
||||
XCTAssertEqual(socket.testHandlers.count, 2)
|
||||
socket.off(clientEvent: .disconnect)
|
||||
XCTAssertEqual(socket.testHandlers.count, 1)
|
||||
XCTAssertTrue(socket.testHandlers.contains(where: { $0.event == "connect" }))
|
||||
}
|
||||
|
||||
func testOffWithId() {
|
||||
let handler = socket.on("test") {data, ack in }
|
||||
XCTAssertEqual(socket.testHandlers.count, 1)
|
||||
socket.on("test") {data, ack in }
|
||||
XCTAssertEqual(socket.testHandlers.count, 2)
|
||||
socket.off(id: handler)
|
||||
XCTAssertEqual(socket.testHandlers.count, 1)
|
||||
}
|
||||
|
||||
func testHandlesErrorPacket() {
|
||||
let expect = expectation(description: "Handled error")
|
||||
socket.on("error") {data, ack in
|
||||
if let error = data[0] as? String, error == "test error" {
|
||||
expect.fulfill()
|
||||
}
|
||||
}
|
||||
|
||||
manager.parseEngineMessage("4\"test error\"")
|
||||
waitForExpectations(timeout: 3, handler: nil)
|
||||
}
|
||||
|
||||
func testHandleBinaryEvent() {
|
||||
let expect = expectation(description: "handled binary event")
|
||||
socket.on("test") {data, ack in
|
||||
if let dict = data[0] as? [String: Any], let data = dict["test"] as? Data {
|
||||
XCTAssertEqual(data as Data, self.data)
|
||||
expect.fulfill()
|
||||
}
|
||||
}
|
||||
|
||||
manager.parseEngineMessage("51-[\"test\",{\"test\":{\"_placeholder\":true,\"num\":0}}]")
|
||||
manager.parseEngineBinaryData(data)
|
||||
waitForExpectations(timeout: 3, handler: nil)
|
||||
}
|
||||
|
||||
func testHandleMultipleBinaryEvent() {
|
||||
let expect = expectation(description: "handled multiple binary event")
|
||||
socket.on("test") {data, ack in
|
||||
if let dict = data[0] as? [String: Any], let data = dict["test"] as? Data,
|
||||
let data2 = dict["test2"] as? Data {
|
||||
XCTAssertEqual(data as Data, self.data)
|
||||
XCTAssertEqual(data2 as Data, self.data2)
|
||||
expect.fulfill()
|
||||
}
|
||||
}
|
||||
|
||||
manager.parseEngineMessage("52-[\"test\",{\"test\":{\"_placeholder\":true,\"num\":0},\"test2\":{\"_placeholder\":true,\"num\":1}}]")
|
||||
manager.parseEngineBinaryData(data)
|
||||
manager.parseEngineBinaryData(data2)
|
||||
waitForExpectations(timeout: 3, handler: nil)
|
||||
}
|
||||
|
||||
func testChangingStatusCallsStatusChangeHandler() {
|
||||
let expect = expectation(description: "The client should announce when the status changes")
|
||||
let statusChange = SocketIOStatus.connecting
|
||||
|
||||
socket.on("statusChange") {data, ack in
|
||||
guard let status = data[0] as? SocketIOStatus else {
|
||||
XCTFail("Status should be one of the defined statuses")
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
XCTAssertEqual(status, statusChange, "The status changed should be the one set")
|
||||
|
||||
expect.fulfill()
|
||||
}
|
||||
|
||||
socket.setTestStatus(statusChange)
|
||||
|
||||
waitForExpectations(timeout: 0.2)
|
||||
}
|
||||
|
||||
func testOnClientEvent() {
|
||||
let expect = expectation(description: "The client should call client event handlers")
|
||||
let event = SocketClientEvent.disconnect
|
||||
let closeReason = "testing"
|
||||
|
||||
socket.on(clientEvent: event) {data, ack in
|
||||
guard let reason = data[0] as? String else {
|
||||
XCTFail("Client should pass data for client events")
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
XCTAssertEqual(closeReason, reason, "The data should be what was sent to handleClientEvent")
|
||||
|
||||
expect.fulfill()
|
||||
}
|
||||
|
||||
socket.handleClientEvent(event, data: [closeReason])
|
||||
|
||||
waitForExpectations(timeout: 0.2)
|
||||
}
|
||||
|
||||
func testClientEventsAreBackwardsCompatible() {
|
||||
let expect = expectation(description: "The client should call old style client event handlers")
|
||||
let event = SocketClientEvent.disconnect
|
||||
let closeReason = "testing"
|
||||
|
||||
socket.on("disconnect") {data, ack in
|
||||
guard let reason = data[0] as? String else {
|
||||
XCTFail("Client should pass data for client events")
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
XCTAssertEqual(closeReason, reason, "The data should be what was sent to handleClientEvent")
|
||||
|
||||
expect.fulfill()
|
||||
}
|
||||
|
||||
socket.handleClientEvent(event, data: [closeReason])
|
||||
|
||||
waitForExpectations(timeout: 0.2)
|
||||
}
|
||||
|
||||
func testConnectTimesOutIfNotConnected() {
|
||||
let expect = expectation(description: "The client should call the timeout function")
|
||||
|
||||
socket = manager.socket(forNamespace: "/someNamespace")
|
||||
socket.setTestStatus(.notConnected)
|
||||
manager.engine = TestEngine(client: manager, url: manager.socketURL, options: nil)
|
||||
|
||||
socket.connect(timeoutAfter: 0.5, withHandler: {
|
||||
expect.fulfill()
|
||||
})
|
||||
|
||||
waitForExpectations(timeout: 0.8)
|
||||
}
|
||||
|
||||
func testConnectDoesNotTimeOutIfConnected() {
|
||||
let expect = expectation(description: "The client should not call the timeout function")
|
||||
|
||||
socket.setTestStatus(.notConnected)
|
||||
manager.engine = TestEngine(client: manager, url: manager.socketURL, options: nil)
|
||||
|
||||
socket.on(clientEvent: .connect) {data, ack in
|
||||
expect.fulfill()
|
||||
}
|
||||
|
||||
socket.connect(timeoutAfter: 0.5, withHandler: {
|
||||
XCTFail("Should not call timeout handler if status is connected")
|
||||
})
|
||||
|
||||
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 0.1) {
|
||||
// Fake connecting
|
||||
self.manager.parseEngineMessage("0/")
|
||||
}
|
||||
|
||||
waitForExpectations(timeout: 2)
|
||||
}
|
||||
|
||||
func testClientCallsConnectOnEngineOpen() {
|
||||
let expect = expectation(description: "The client call the connect handler")
|
||||
let eng = TestEngine(client: manager, url: manager.socketURL, options: nil)
|
||||
|
||||
eng.onConnect = {
|
||||
self.socket.didConnect(toNamespace: self.socket.nsp, payload: nil)
|
||||
}
|
||||
|
||||
manager.engine = eng
|
||||
socket.setTestStatus(.notConnected)
|
||||
|
||||
socket.on(clientEvent: .connect) {data, ack in
|
||||
expect.fulfill()
|
||||
}
|
||||
|
||||
socket.connect(timeoutAfter: 0.5, withHandler: {
|
||||
XCTFail("Should not call timeout handler if status is connected")
|
||||
})
|
||||
|
||||
waitForExpectations(timeout: 2)
|
||||
}
|
||||
|
||||
func testConnectIsCalledWithNamespace() {
|
||||
let expect = expectation(description: "The client should not call the timeout function")
|
||||
let nspString = "/swift"
|
||||
|
||||
socket = manager.socket(forNamespace: "/swift")
|
||||
socket.setTestStatus(.notConnected)
|
||||
manager.engine = TestEngine(client: manager, url: manager.socketURL, options: nil)
|
||||
|
||||
socket.on(clientEvent: .connect) {data, ack in
|
||||
guard let nsp = data[0] as? String else {
|
||||
XCTFail("Connect should be called with a namespace")
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
XCTAssertEqual(nspString, nsp, "It should connect with the correct namespace")
|
||||
|
||||
expect.fulfill()
|
||||
}
|
||||
|
||||
socket.connect(timeoutAfter: 0.3, withHandler: {
|
||||
XCTFail("Should not call timeout handler if status is connected")
|
||||
})
|
||||
|
||||
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 0.1) {
|
||||
// Fake connecting
|
||||
self.manager.parseEngineMessage("0/swift")
|
||||
}
|
||||
|
||||
waitForExpectations(timeout: 2)
|
||||
}
|
||||
|
||||
func testErrorInCustomSocketDataCallsErrorHandler() {
|
||||
let expect = expectation(description: "The client should call the error handler for emit errors because of " +
|
||||
"custom data")
|
||||
|
||||
socket.on(clientEvent: .error) {data, ack in
|
||||
guard data.count == 3, data[0] as? String == "myEvent",
|
||||
data[2] is ThrowingData.ThrowingError else {
|
||||
XCTFail("Incorrect error call")
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
expect.fulfill()
|
||||
}
|
||||
|
||||
socket.emit("myEvent", ThrowingData())
|
||||
|
||||
waitForExpectations(timeout: 0.2)
|
||||
}
|
||||
|
||||
func testErrorInCustomSocketDataCallsErrorHandler_ack() {
|
||||
let expect = expectation(description: "The client should call the error handler for emit errors because of " +
|
||||
"custom data")
|
||||
|
||||
socket.on(clientEvent: .error) {data, ack in
|
||||
guard data.count == 3, data[0] as? String == "myEvent",
|
||||
data[2] is ThrowingData.ThrowingError else {
|
||||
XCTFail("Incorrect error call")
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
expect.fulfill()
|
||||
}
|
||||
|
||||
socket.emitWithAck("myEvent", ThrowingData()).timingOut(after: 0.8, callback: {_ in
|
||||
XCTFail("Ack callback should not be called")
|
||||
})
|
||||
|
||||
waitForExpectations(timeout: 0.2)
|
||||
}
|
||||
|
||||
func testSettingConfigAfterInit() {
|
||||
socket.setTestStatus(.notConnected)
|
||||
manager.config.insert(.log(true))
|
||||
|
||||
XCTAssertTrue(DefaultSocketLogger.Logger.log, "It should set logging to true after creation")
|
||||
|
||||
manager.config = [.log(false)]
|
||||
|
||||
XCTAssertFalse(DefaultSocketLogger.Logger.log, "It should set logging to false after creation")
|
||||
}
|
||||
|
||||
func testSettingConfigAfterDisconnect() {
|
||||
socket.setTestStatus(.disconnected)
|
||||
manager.config.insert(.log(true))
|
||||
|
||||
XCTAssertTrue(DefaultSocketLogger.Logger.log, "It should set logging to true after creation")
|
||||
|
||||
manager.config = [.log(false)]
|
||||
|
||||
XCTAssertFalse(DefaultSocketLogger.Logger.log, "It should set logging to false after creation")
|
||||
}
|
||||
|
||||
func testSettingConfigAfterInitWhenConnectedDoesNotIgnoreChanges() {
|
||||
manager.setTestStatus(.connected)
|
||||
manager.config = [.log(true)]
|
||||
|
||||
XCTAssertTrue(DefaultSocketLogger.Logger.log, "It should set logging to false after creation")
|
||||
}
|
||||
|
||||
func testClientCallsSentPingHandler() {
|
||||
let expect = expectation(description: "The client should emit a ping event")
|
||||
|
||||
socket.on(clientEvent: .pong) {data, ack in
|
||||
expect.fulfill()
|
||||
}
|
||||
|
||||
manager.engineDidSendPong()
|
||||
|
||||
waitForExpectations(timeout: 0.2)
|
||||
}
|
||||
|
||||
func testClientCallsGotPongHandler() {
|
||||
let expect = expectation(description: "The client should emit a pong event")
|
||||
|
||||
socket.on(clientEvent: .ping) {data, ack in
|
||||
expect.fulfill()
|
||||
}
|
||||
|
||||
manager.engineDidReceivePing()
|
||||
|
||||
waitForExpectations(timeout: 0.2)
|
||||
}
|
||||
|
||||
let data = "test".data(using: String.Encoding.utf8)!
|
||||
let data2 = "test2".data(using: String.Encoding.utf8)!
|
||||
|
||||
private var manager: SocketManager!
|
||||
private var socket: SocketIOClient!
|
||||
|
||||
override func setUp() {
|
||||
super.setUp()
|
||||
|
||||
manager = SocketManager(socketURL: URL(string: "http://localhost/")!, config: [.log(false)])
|
||||
socket = manager.defaultSocket
|
||||
socket.setTestable()
|
||||
}
|
||||
}
|
||||
|
||||
struct ThrowingData: SocketData {
|
||||
enum ThrowingError : Error {
|
||||
case error
|
||||
}
|
||||
|
||||
func socketRepresentation() throws -> SocketData {
|
||||
throw ThrowingError.error
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class TestEngine: SocketEngineSpec {
|
||||
weak var client: SocketEngineClient?
|
||||
private(set) var closed = false
|
||||
private(set) var compress = false
|
||||
private(set) var connected = false
|
||||
var connectParams: [String: Any]? = nil
|
||||
private(set) var cookies: [HTTPCookie]? = nil
|
||||
private(set) var engineQueue = DispatchQueue.main
|
||||
var extraHeaders: [String: String]? = nil
|
||||
private(set) var fastUpgrade = false
|
||||
private(set) var forcePolling = false
|
||||
private(set) var forceWebsockets = false
|
||||
private(set) var polling = false
|
||||
private(set) var probing = false
|
||||
private(set) var sid = ""
|
||||
private(set) var socketPath = ""
|
||||
private(set) var urlPolling = URL(string: "http://localhost/")!
|
||||
private(set) var urlWebSocket = URL(string: "http://localhost/")!
|
||||
private(set) var websocket = false
|
||||
private(set) var ws: WebSocket? = nil
|
||||
private(set) var version = SocketIOVersion.three
|
||||
|
||||
internal var onConnect: (() -> ())?
|
||||
|
||||
required init(client: SocketEngineClient, url: URL, options: [String: Any]?) {
|
||||
self.client = client
|
||||
}
|
||||
|
||||
func connect() {
|
||||
onConnect?()
|
||||
}
|
||||
|
||||
func didError(reason: String) { }
|
||||
func disconnect(reason: String) { }
|
||||
func doFastUpgrade() { }
|
||||
func flushWaitingForPostToWebSocket() { }
|
||||
func parseEngineData(_ data: Data) { }
|
||||
func parseEngineMessage(_ message: String) { }
|
||||
func write(_ msg: String, withType type: SocketEnginePacketType, withData data: [Data], completion: (() -> ())?) { }
|
||||
}
|
||||
13
Tests/TestSocketIO/utils.swift
Normal file
13
Tests/TestSocketIO/utils.swift
Normal file
@ -0,0 +1,13 @@
|
||||
//
|
||||
// Created by Erik Little on 2019-01-11.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
@testable import SocketIO
|
||||
|
||||
public class OBjcUtils: NSObject {
|
||||
@objc
|
||||
public static func setTestStatus(socket: SocketIOClient, status: SocketIOStatus) {
|
||||
socket.setTestStatus(status)
|
||||
}
|
||||
}
|
||||
109
Usage Docs/12to13.md
Normal file
109
Usage Docs/12to13.md
Normal file
@ -0,0 +1,109 @@
|
||||
# Upgrading from v12
|
||||
|
||||
This guide will help you navigate the changes that were introduced in v13.
|
||||
|
||||
## What are the big changes?
|
||||
|
||||
The biggest change is how to create and manage clients. Much like the native JS client and server,
|
||||
the swift client now only uses one engine per connection. Previously in order to use namespaces it was required
|
||||
to create multiple clients, and each client had its own engine.
|
||||
|
||||
Some v12 code might've looked like this:
|
||||
|
||||
```swift
|
||||
let defaultSocket = SocketIOClient(socketURL: myURL)
|
||||
let namespaceSocket = SocketIOClient(socketURL: myURL, config: [.nsp("/swift")])
|
||||
|
||||
// add handlers for sockets and connect
|
||||
|
||||
```
|
||||
|
||||
In v12 this would have opened two connections to the socket.io.
|
||||
|
||||
|
||||
In v13 the same code would look like this:
|
||||
|
||||
```swift
|
||||
let manager = SocketManager(socketURL: myURL)
|
||||
let defaultSocket = manager.defaultSocket
|
||||
let namespaceSocket = manager.socket(forNamespace: "/swift")
|
||||
|
||||
// add handlers for sockets and connect
|
||||
```
|
||||
|
||||
In v13 `defaultSocket` and `namespaceSocket` will share a single transport. This means one less connection to the server
|
||||
needs to be opened.
|
||||
|
||||
## What might I have to change?
|
||||
|
||||
- The most obvious thing you will need to change is that instead of creating `SocketIOClient`s directly, you will create a
|
||||
`SocketManager` and either use the `defaultSocket` property if you don't need namespaces, or call the
|
||||
`socket(forNamespace:)` method on the manager.
|
||||
|
||||
- `SocketIOClient` is no longer a client to an engine. So if you were overriding the engine methods, these have been moved
|
||||
to the manager.
|
||||
|
||||
- The library is now a single target. So you might have to change some of your Xcode project settings.
|
||||
|
||||
- `SocketIOClient`s no longer take a configuration, they are shared from the manager.
|
||||
|
||||
- The `joinNamespace()` and `leaveNamespace()` methods on `SocketIOClient` no longer take any arguments, and in most cases
|
||||
no longer need to be called. Namespace joining/leaving can be managed by calling `connect()`/`disconnect()` on the socket
|
||||
associated with that namespace.
|
||||
|
||||
----------
|
||||
|
||||
# What things should I know?
|
||||
|
||||
How sockets are stored
|
||||
---
|
||||
|
||||
You should know that `SocketIOClient`s no longer need to be held around in properties, but the `SocketManager` should.
|
||||
|
||||
One of the most common mistakes people made is not maintaining a strong reference to the client.
|
||||
|
||||
```swift
|
||||
class Manager {
|
||||
func addHandlers() {
|
||||
let socket = SocketIOClient(socketURL: myURL, config: [.nsp("/swift")])
|
||||
|
||||
// Add handlers
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
This would have resulted in the client being released and no handlers being called.
|
||||
|
||||
A *correct* equivalent would be:
|
||||
|
||||
```swift
|
||||
class Manager {
|
||||
let socketManager = SocketManager(socketURL: someURL)
|
||||
|
||||
func addHandlers() {
|
||||
let socket = socketManager.socket(forNamespace: "/swift")
|
||||
|
||||
// Add handlers
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
This code is fine because the `SocketManager` will maintain a strong reference to the socket.
|
||||
|
||||
It's also worth noting that subsequent calls to `socket(forNamespace:)` will return the *same* socket instance as the
|
||||
first call. So you don't need to hold onto the socket directly just to access it again, just call `socket(forNamespace:)`
|
||||
on the manager to get it. **This does mean that if you need multiple sockets on the same namespace, you will have to use
|
||||
multiple managers.**
|
||||
|
||||
What to call connect on
|
||||
---
|
||||
|
||||
Connect can either be called on the manager directly, or on one of the sockets made from it. In either case, if the manager
|
||||
was not already connected to the server, a connection will be made. Also in both cases the default socket (namespace "/")
|
||||
will fire a `connect` event.
|
||||
|
||||
The difference is that if `connect()` is just called on the manager, then any sockets for that manager that are not the default
|
||||
socket will not automatically connect. `connect()` will need to be called individually for each socket. However, if `connect()`
|
||||
is called on a client, then in addition to opening the connection if needed, the client will connect to its namespace,
|
||||
and a `connect` event fired.
|
||||
|
||||
35
Usage Docs/15to16.md
Normal file
35
Usage Docs/15to16.md
Normal file
@ -0,0 +1,35 @@
|
||||
# Upgrading from v15 to v16
|
||||
|
||||
This guide will help you navigate the changes that were introduced in v16.
|
||||
|
||||
## Objective-c is no longer supported. You must now use Swift.
|
||||
|
||||
## Client supports multiple socket.io versions
|
||||
|
||||
The client now supports socket.io 3 servers. This is mostly a transparent change, however if your server
|
||||
is socket.io 2, you must send `.version(.two)` as an option to the manager.
|
||||
|
||||
```swift
|
||||
SocketManager(socketURL: URL(string:"http://localhost:8087/")!, config: [.version(.two)])
|
||||
```
|
||||
|
||||
## How to upgrade
|
||||
|
||||
- first, upgrade the Socket.IO server to v4 with the compatibility mode enabled (`allowEIO3: true`)
|
||||
- then, upgrade the clients to v16
|
||||
- finally, once all clients have upgraded, disable the compatibility mode
|
||||
|
||||
You can check the version of the connection on the server side with:
|
||||
|
||||
```js
|
||||
io.on("connection", (socket) => {
|
||||
// either 3 for the 3rd revision of the protocol (Socket.IO v2) or 4 for the 4th revision (Socket.IO v3/v4)
|
||||
const version = socket.conn.protocol;
|
||||
});
|
||||
```
|
||||
|
||||
See also:
|
||||
|
||||
- [Compatibility table](https://nuclearace.github.io/Socket.IO-Client-Swift/Compatibility.html)
|
||||
- Migrating from 2.x to 3.0: https://socket.io/docs/v4/migrating-from-2-x-to-3-0/
|
||||
- Migrating from 3.x to 4.0: https://socket.io/docs/v4/migrating-from-3-x-to-4-0/
|
||||
61
Usage Docs/Compatibility.md
Normal file
61
Usage Docs/Compatibility.md
Normal file
@ -0,0 +1,61 @@
|
||||
Here is the compatibility table with the Node.js server:
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<th rowspan="2">Swift Client version</th>
|
||||
<th colspan="3">Socket.IO server version</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center">2.x</td>
|
||||
<td align="center">3.x</td>
|
||||
<td align="center">4.x</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center">v15.x</td>
|
||||
<td align="center"><b>YES</b></td>
|
||||
<td align="center"><b>YES</b><sup>1</sup></td>
|
||||
<td align="center"><b>YES</b><sup>2</sup></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center">v16.x</td>
|
||||
<td align="center"><b>YES</b><sup>3</sup></td>
|
||||
<td align="center"><b>YES</b></td>
|
||||
<td align="center"><b>YES</b></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
[1] Yes, with <code><a href="https://socket.io/docs/v4/server-initialization/#allowEIO3">allowEIO3: true</a></code> (server) and `.connectParams(["EIO": "3"])` (client):
|
||||
|
||||
*Server*
|
||||
|
||||
```js
|
||||
const { createServer } = require("http");
|
||||
const { Server } = require("socket.io");
|
||||
|
||||
const httpServer = createServer();
|
||||
const io = new Server(httpServer, {
|
||||
allowEIO3: true
|
||||
});
|
||||
|
||||
httpServer.listen(8080);
|
||||
```
|
||||
|
||||
*Client*
|
||||
|
||||
```swift
|
||||
SocketManager(socketURL: URL(string:"http://localhost:8080/")!, config: [.connectParams(["EIO": "3"])])
|
||||
```
|
||||
|
||||
[2] Yes, <code><a href="https://socket.io/docs/v4/server-initialization/#allowEIO3">allowEIO3: true</a></code> (server)
|
||||
|
||||
[3] Yes, with `.version(.two)` (client):
|
||||
|
||||
```swift
|
||||
SocketManager(socketURL: URL(string:"http://localhost:8080/")!, config: [.version(.two)])
|
||||
```
|
||||
|
||||
See also:
|
||||
|
||||
- Migrating from 2.x to 3.0: https://socket.io/docs/v4/migrating-from-2-x-to-3-0/
|
||||
- Migrating from 3.x to 4.0: https://socket.io/docs/v4/migrating-from-3-x-to-4-0/
|
||||
- Socket.IO protocol: https://github.com/socketio/socket.io-protocol
|
||||
44
Usage Docs/FAQ.md
Normal file
44
Usage Docs/FAQ.md
Normal file
@ -0,0 +1,44 @@
|
||||
## How do I connect to my WebSocket server?
|
||||
|
||||
This library is **NOT** a WebSockets library. This library is only for servers that implement the socket.io protocol,
|
||||
such as [socket.io](https://socket.io/). If you need a plain WebSockets client check out
|
||||
[Starscream](https://github.com/daltoniam/Starscream) for Swift and [JetFire](https://github.com/acmacalister/jetfire)
|
||||
for Objective-C.
|
||||
|
||||
## Why isn't my event handler being called?
|
||||
|
||||
One of the most common reasons your event might not be called is if the client is released by
|
||||
[ARC](https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/AutomaticReferenceCounting.html).
|
||||
|
||||
Take this code for example:
|
||||
|
||||
```swift
|
||||
class Manager {
|
||||
func addHandlers() {
|
||||
let manager = SocketManager(socketURL: URL(string: "http://somesocketioserver.com")!)
|
||||
|
||||
manager.defaultSocket.on("myEvent") {data, ack in
|
||||
print(data)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
This code is **incorrect**, and the event handler will never be called. Because as soon as this method is called `manager`
|
||||
will be released, along with the socket, and its memory reclaimed.
|
||||
|
||||
A correct way would be:
|
||||
|
||||
```swift
|
||||
class Manager {
|
||||
let manager = SocketManager(socketURL: URL(string: "http://somesocketioserver.com")!)
|
||||
|
||||
func addHandlers() {
|
||||
manager.defaultSocket.on("myEvent") {data, ack in
|
||||
print(data)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
335
docs/12to13.html
Normal file
335
docs/12to13.html
Normal file
@ -0,0 +1,335 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>12to13 Reference</title>
|
||||
<link rel="stylesheet" type="text/css" href="css/jazzy.css" />
|
||||
<link rel="stylesheet" type="text/css" href="css/highlight.css" />
|
||||
<meta charset="utf-8">
|
||||
<script src="js/jquery.min.js" defer></script>
|
||||
<script src="js/jazzy.js" defer></script>
|
||||
|
||||
<script src="js/lunr.min.js" defer></script>
|
||||
<script src="js/typeahead.jquery.js" defer></script>
|
||||
<script src="js/jazzy.search.js" defer></script>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
|
||||
<a title="12to13 Reference"></a>
|
||||
|
||||
<header class="header">
|
||||
<p class="header-col header-col--primary">
|
||||
<a class="header-link" href="index.html">
|
||||
SocketIO 16.0.0 Docs
|
||||
</a>
|
||||
(100% documented)
|
||||
</p>
|
||||
|
||||
<p class="header-col--secondary">
|
||||
<form role="search" action="search.json">
|
||||
<input type="text" placeholder="Search documentation" data-typeahead>
|
||||
</form>
|
||||
</p>
|
||||
|
||||
|
||||
</header>
|
||||
|
||||
<p class="breadcrumbs">
|
||||
<a class="breadcrumb" href="index.html">SocketIO Reference</a>
|
||||
<img class="carat" src="img/carat.png" />
|
||||
12to13 Reference
|
||||
</p>
|
||||
|
||||
<div class="content-wrapper">
|
||||
<nav class="navigation">
|
||||
<ul class="nav-groups">
|
||||
<li class="nav-group-name">
|
||||
<a class="nav-group-name-link" href="Guides.html">Guides</a>
|
||||
<ul class="nav-group-tasks">
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="12to13.html">12to13</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="15to16.html">15to16</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="faq.html">FAQ</a>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="nav-group-name">
|
||||
<a class="nav-group-name-link" href="Classes.html">Classes</a>
|
||||
<ul class="nav-group-tasks">
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="Classes/OnAckCallback.html">OnAckCallback</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="Classes/SocketAckEmitter.html">SocketAckEmitter</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="Classes/SocketAnyEvent.html">SocketAnyEvent</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="Classes/SocketEngine.html">SocketEngine</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="Classes/SocketIOClient.html">SocketIOClient</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="Classes/SocketManager.html">SocketManager</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="Classes/SocketRawAckView.html">SocketRawAckView</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="Classes/SocketRawView.html">SocketRawView</a>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="nav-group-name">
|
||||
<a class="nav-group-name-link" href="Enums.html">Enumerations</a>
|
||||
<ul class="nav-group-tasks">
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="Enums/SocketAckStatus.html">SocketAckStatus</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="Enums/SocketClientEvent.html">SocketClientEvent</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="Enums/SocketEnginePacketType.html">SocketEnginePacketType</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="Enums/SocketIOClientOption.html">SocketIOClientOption</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="Enums/SocketIOStatus.html">SocketIOStatus</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="Enums/SocketIOVersion.html">SocketIOVersion</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="Enums/SocketParsableError.html">SocketParsableError</a>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="nav-group-name">
|
||||
<a class="nav-group-name-link" href="Extensions.html">Extensions</a>
|
||||
<ul class="nav-group-tasks">
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="Extensions.html#/s:Sa">Array</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="Extensions.html#/s:Sb">Bool</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="Extensions.html#/s:10Foundation4DataV">Data</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="Extensions.html#/s:SD">Dictionary</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="Extensions.html#/s:Sd">Double</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="Extensions.html#/s:Si">Int</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="Extensions.html#/c:objc(cs)NSArray">NSArray</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="Extensions.html#/c:objc(cs)NSData">NSData</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="Extensions.html#/c:objc(cs)NSDictionary">NSDictionary</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="Extensions.html#/c:objc(cs)NSNull">NSNull</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="Extensions.html#/c:objc(cs)NSString">NSString</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="Extensions.html#/s:SS">String</a>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="nav-group-name">
|
||||
<a class="nav-group-name-link" href="Protocols.html">Protocols</a>
|
||||
<ul class="nav-group-tasks">
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="Protocols/ConfigSettable.html">ConfigSettable</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="Protocols/SocketData.html">SocketData</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="Protocols/SocketDataBufferable.html">SocketDataBufferable</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="Protocols/SocketEngineClient.html">SocketEngineClient</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="Protocols/SocketEnginePollable.html">SocketEnginePollable</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="Protocols/SocketEngineSpec.html">SocketEngineSpec</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="Protocols/SocketEngineWebsocket.html">SocketEngineWebsocket</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="Protocols/SocketIOClientSpec.html">SocketIOClientSpec</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="Protocols/SocketLogger.html">SocketLogger</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="Protocols/SocketManagerSpec.html">SocketManagerSpec</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="Protocols/SocketParsable.html">SocketParsable</a>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="nav-group-name">
|
||||
<a class="nav-group-name-link" href="Structs.html">Structures</a>
|
||||
<ul class="nav-group-tasks">
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="Structs/SocketEventHandler.html">SocketEventHandler</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="Structs/SocketIOClientConfiguration.html">SocketIOClientConfiguration</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="Structs/SocketPacket.html">SocketPacket</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="Structs/SocketPacket/PacketType.html">– PacketType</a>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="nav-group-name">
|
||||
<a class="nav-group-name-link" href="Typealiases.html">Type Aliases</a>
|
||||
<ul class="nav-group-tasks">
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="Typealiases.html#/s:8SocketIO11AckCallbacka">AckCallback</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="Typealiases.html#/s:8SocketIO14NormalCallbacka">NormalCallback</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="Typealiases.html#/s:8SocketIO4Posta">Post</a>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
<article class="main-content">
|
||||
|
||||
<section class="section">
|
||||
<div class="section-content top-matter">
|
||||
|
||||
<h1 id='upgrading-from-v12' class='heading'>Upgrading from v12</h1>
|
||||
|
||||
<p>This guide will help you navigate the changes that were introduced in v13.</p>
|
||||
<h2 id='what-are-the-big-changes' class='heading'>What are the big changes?</h2>
|
||||
|
||||
<p>The biggest change is how to create and manage clients. Much like the native JS client and server,
|
||||
the swift client now only uses one engine per connection. Previously in order to use namespaces it was required
|
||||
to create multiple clients, and each client had its own engine.</p>
|
||||
|
||||
<p>Some v12 code might’ve looked like this:</p>
|
||||
<pre class="highlight swift"><code><span class="k">let</span> <span class="nv">defaultSocket</span> <span class="o">=</span> <span class="kt">SocketIOClient</span><span class="p">(</span><span class="nv">socketURL</span><span class="p">:</span> <span class="n">myURL</span><span class="p">)</span>
|
||||
<span class="k">let</span> <span class="nv">namespaceSocket</span> <span class="o">=</span> <span class="kt">SocketIOClient</span><span class="p">(</span><span class="nv">socketURL</span><span class="p">:</span> <span class="n">myURL</span><span class="p">,</span> <span class="nv">config</span><span class="p">:</span> <span class="p">[</span><span class="o">.</span><span class="nf">nsp</span><span class="p">(</span><span class="s">"/swift"</span><span class="p">)])</span>
|
||||
|
||||
<span class="c1">// add handlers for sockets and connect</span>
|
||||
|
||||
</code></pre>
|
||||
|
||||
<p>In v12 this would have opened two connections to the socket.io.</p>
|
||||
|
||||
<p>In v13 the same code would look like this:</p>
|
||||
<pre class="highlight swift"><code><span class="k">let</span> <span class="nv">manager</span> <span class="o">=</span> <span class="kt">SocketManager</span><span class="p">(</span><span class="nv">socketURL</span><span class="p">:</span> <span class="n">myURL</span><span class="p">)</span>
|
||||
<span class="k">let</span> <span class="nv">defaultSocket</span> <span class="o">=</span> <span class="n">manager</span><span class="o">.</span><span class="n">defaultSocket</span>
|
||||
<span class="k">let</span> <span class="nv">namespaceSocket</span> <span class="o">=</span> <span class="n">manager</span><span class="o">.</span><span class="nf">socket</span><span class="p">(</span><span class="nv">forNamespace</span><span class="p">:</span> <span class="s">"/swift"</span><span class="p">)</span>
|
||||
|
||||
<span class="c1">// add handlers for sockets and connect</span>
|
||||
</code></pre>
|
||||
|
||||
<p>In v13 <code>defaultSocket</code> and <code>namespaceSocket</code> will share a single transport. This means one less connection to the server
|
||||
needs to be opened. </p>
|
||||
<h2 id='what-might-i-have-to-change' class='heading'>What might I have to change?</h2>
|
||||
|
||||
<ul>
|
||||
<li><p>The most obvious thing you will need to change is that instead of creating <code><a href="Classes/SocketIOClient.html">SocketIOClient</a></code>s directly, you will create a
|
||||
<code><a href="Classes/SocketManager.html">SocketManager</a></code> and either use the <code>defaultSocket</code> property if you don’t need namespaces, or call the
|
||||
<code>socket(forNamespace:)</code> method on the manager.</p></li>
|
||||
<li><p><code><a href="Classes/SocketIOClient.html">SocketIOClient</a></code> is no longer a client to an engine. So if you were overriding the engine methods, these have been moved
|
||||
to the manager. </p></li>
|
||||
<li><p>The library is now a single target. So you might have to change some of your Xcode project settings.</p></li>
|
||||
<li><p><code><a href="Classes/SocketIOClient.html">SocketIOClient</a></code>s no longer take a configuration, they are shared from the manager.</p></li>
|
||||
<li><p>The <code>joinNamespace()</code> and <code>leaveNamespace()</code> methods on <code><a href="Classes/SocketIOClient.html">SocketIOClient</a></code> no longer take any arguments, and in most cases
|
||||
no longer need to be called. Namespace joining/leaving can be managed by calling <code>connect()</code>/<code>disconnect()</code> on the socket
|
||||
associated with that namespace.</p></li>
|
||||
</ul>
|
||||
|
||||
<hr>
|
||||
<h1 id='what-things-should-i-know' class='heading'>What things should I know?</h1>
|
||||
<h2 id='how-sockets-are-stored' class='heading'>How sockets are stored</h2>
|
||||
|
||||
<p>You should know that <code><a href="Classes/SocketIOClient.html">SocketIOClient</a></code>s no longer need to be held around in properties, but the <code><a href="Classes/SocketManager.html">SocketManager</a></code> should.</p>
|
||||
|
||||
<p>One of the most common mistakes people made is not maintaining a strong reference to the client.</p>
|
||||
<pre class="highlight swift"><code><span class="kd">class</span> <span class="kt">Manager</span> <span class="p">{</span>
|
||||
<span class="kd">func</span> <span class="nf">addHandlers</span><span class="p">()</span> <span class="p">{</span>
|
||||
<span class="k">let</span> <span class="nv">socket</span> <span class="o">=</span> <span class="kt">SocketIOClient</span><span class="p">(</span><span class="nv">socketURL</span><span class="p">:</span> <span class="n">myURL</span><span class="p">,</span> <span class="nv">config</span><span class="p">:</span> <span class="p">[</span><span class="o">.</span><span class="nf">nsp</span><span class="p">(</span><span class="s">"/swift"</span><span class="p">)])</span>
|
||||
|
||||
<span class="c1">// Add handlers</span>
|
||||
<span class="p">}</span>
|
||||
<span class="p">}</span>
|
||||
</code></pre>
|
||||
|
||||
<p>This would have resulted in the client being released and no handlers being called.</p>
|
||||
|
||||
<p>A <em>correct</em> equivalent would be:</p>
|
||||
<pre class="highlight swift"><code><span class="kd">class</span> <span class="kt">Manager</span> <span class="p">{</span>
|
||||
<span class="k">let</span> <span class="nv">socketManager</span> <span class="o">=</span> <span class="kt">SocketManager</span><span class="p">(</span><span class="nv">socketURL</span><span class="p">:</span> <span class="n">someURL</span><span class="p">)</span>
|
||||
|
||||
<span class="kd">func</span> <span class="nf">addHandlers</span><span class="p">()</span> <span class="p">{</span>
|
||||
<span class="k">let</span> <span class="nv">socket</span> <span class="o">=</span> <span class="n">socketManager</span><span class="o">.</span><span class="nf">socket</span><span class="p">(</span><span class="nv">forNamespace</span><span class="p">:</span> <span class="s">"/swift"</span><span class="p">)</span>
|
||||
|
||||
<span class="c1">// Add handlers</span>
|
||||
<span class="p">}</span>
|
||||
<span class="p">}</span>
|
||||
</code></pre>
|
||||
|
||||
<p>This code is fine because the <code><a href="Classes/SocketManager.html">SocketManager</a></code> will maintain a strong reference to the socket.</p>
|
||||
|
||||
<p>It’s also worth noting that subsequent calls to <code>socket(forNamespace:)</code> will return the <em>same</em> socket instance as the
|
||||
first call. So you don’t need to hold onto the socket directly just to access it again, just call <code>socket(forNamespace:)</code>
|
||||
on the manager to get it. <strong>This does mean that if you need multiple sockets on the same namespace, you will have to use
|
||||
multiple managers.</strong></p>
|
||||
<h2 id='what-to-call-connect-on' class='heading'>What to call connect on</h2>
|
||||
|
||||
<p>Connect can either be called on the manager directly, or on one of the sockets made from it. In either case, if the manager
|
||||
was not already connected to the server, a connection will be made. Also in both cases the default socket (namespace “/”)
|
||||
will fire a <code>connect</code> event. </p>
|
||||
|
||||
<p>The difference is that if <code>connect()</code> is just called on the manager, then any sockets for that manager that are not the default
|
||||
socket will not automatically connect. <code>connect()</code> will need to be called individually for each socket. However, if <code>connect()</code>
|
||||
is called on a client, then in addition to opening the connection if needed, the client will connect to its namespace,
|
||||
and a <code>connect</code> event fired.</p>
|
||||
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
||||
</article>
|
||||
</div>
|
||||
<section class="footer">
|
||||
<p>© 2021 <a class="link" href="https://github.com/socketio/socket.io-client-swift" target="_blank" rel="external">Erik</a>. All rights reserved. (Last updated: 2021-02-01)</p>
|
||||
<p>Generated by <a class="link" href="https://github.com/realm/jazzy" target="_blank" rel="external">jazzy ♪♫ v0.13.6</a>, a <a class="link" href="https://realm.io" target="_blank" rel="external">Realm</a> project.</p>
|
||||
</section>
|
||||
</body>
|
||||
</div>
|
||||
</html>
|
||||
255
docs/15to16.html
Normal file
255
docs/15to16.html
Normal file
@ -0,0 +1,255 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>15to16 Reference</title>
|
||||
<link rel="stylesheet" type="text/css" href="css/jazzy.css" />
|
||||
<link rel="stylesheet" type="text/css" href="css/highlight.css" />
|
||||
<meta charset="utf-8">
|
||||
<script src="js/jquery.min.js" defer></script>
|
||||
<script src="js/jazzy.js" defer></script>
|
||||
|
||||
<script src="js/lunr.min.js" defer></script>
|
||||
<script src="js/typeahead.jquery.js" defer></script>
|
||||
<script src="js/jazzy.search.js" defer></script>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
|
||||
<a title="15to16 Reference"></a>
|
||||
|
||||
<header class="header">
|
||||
<p class="header-col header-col--primary">
|
||||
<a class="header-link" href="index.html">
|
||||
SocketIO 16.0.0 Docs
|
||||
</a>
|
||||
(100% documented)
|
||||
</p>
|
||||
|
||||
<p class="header-col--secondary">
|
||||
<form role="search" action="search.json">
|
||||
<input type="text" placeholder="Search documentation" data-typeahead>
|
||||
</form>
|
||||
</p>
|
||||
|
||||
|
||||
</header>
|
||||
|
||||
<p class="breadcrumbs">
|
||||
<a class="breadcrumb" href="index.html">SocketIO Reference</a>
|
||||
<img class="carat" src="img/carat.png" />
|
||||
15to16 Reference
|
||||
</p>
|
||||
|
||||
<div class="content-wrapper">
|
||||
<nav class="navigation">
|
||||
<ul class="nav-groups">
|
||||
<li class="nav-group-name">
|
||||
<a class="nav-group-name-link" href="Guides.html">Guides</a>
|
||||
<ul class="nav-group-tasks">
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="12to13.html">12to13</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="15to16.html">15to16</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="faq.html">FAQ</a>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="nav-group-name">
|
||||
<a class="nav-group-name-link" href="Classes.html">Classes</a>
|
||||
<ul class="nav-group-tasks">
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="Classes/OnAckCallback.html">OnAckCallback</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="Classes/SocketAckEmitter.html">SocketAckEmitter</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="Classes/SocketAnyEvent.html">SocketAnyEvent</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="Classes/SocketEngine.html">SocketEngine</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="Classes/SocketIOClient.html">SocketIOClient</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="Classes/SocketManager.html">SocketManager</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="Classes/SocketRawAckView.html">SocketRawAckView</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="Classes/SocketRawView.html">SocketRawView</a>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="nav-group-name">
|
||||
<a class="nav-group-name-link" href="Enums.html">Enumerations</a>
|
||||
<ul class="nav-group-tasks">
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="Enums/SocketAckStatus.html">SocketAckStatus</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="Enums/SocketClientEvent.html">SocketClientEvent</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="Enums/SocketEnginePacketType.html">SocketEnginePacketType</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="Enums/SocketIOClientOption.html">SocketIOClientOption</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="Enums/SocketIOStatus.html">SocketIOStatus</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="Enums/SocketIOVersion.html">SocketIOVersion</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="Enums/SocketParsableError.html">SocketParsableError</a>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="nav-group-name">
|
||||
<a class="nav-group-name-link" href="Extensions.html">Extensions</a>
|
||||
<ul class="nav-group-tasks">
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="Extensions.html#/s:Sa">Array</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="Extensions.html#/s:Sb">Bool</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="Extensions.html#/s:10Foundation4DataV">Data</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="Extensions.html#/s:SD">Dictionary</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="Extensions.html#/s:Sd">Double</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="Extensions.html#/s:Si">Int</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="Extensions.html#/c:objc(cs)NSArray">NSArray</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="Extensions.html#/c:objc(cs)NSData">NSData</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="Extensions.html#/c:objc(cs)NSDictionary">NSDictionary</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="Extensions.html#/c:objc(cs)NSNull">NSNull</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="Extensions.html#/c:objc(cs)NSString">NSString</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="Extensions.html#/s:SS">String</a>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="nav-group-name">
|
||||
<a class="nav-group-name-link" href="Protocols.html">Protocols</a>
|
||||
<ul class="nav-group-tasks">
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="Protocols/ConfigSettable.html">ConfigSettable</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="Protocols/SocketData.html">SocketData</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="Protocols/SocketDataBufferable.html">SocketDataBufferable</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="Protocols/SocketEngineClient.html">SocketEngineClient</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="Protocols/SocketEnginePollable.html">SocketEnginePollable</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="Protocols/SocketEngineSpec.html">SocketEngineSpec</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="Protocols/SocketEngineWebsocket.html">SocketEngineWebsocket</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="Protocols/SocketIOClientSpec.html">SocketIOClientSpec</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="Protocols/SocketLogger.html">SocketLogger</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="Protocols/SocketManagerSpec.html">SocketManagerSpec</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="Protocols/SocketParsable.html">SocketParsable</a>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="nav-group-name">
|
||||
<a class="nav-group-name-link" href="Structs.html">Structures</a>
|
||||
<ul class="nav-group-tasks">
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="Structs/SocketEventHandler.html">SocketEventHandler</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="Structs/SocketIOClientConfiguration.html">SocketIOClientConfiguration</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="Structs/SocketPacket.html">SocketPacket</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="Structs/SocketPacket/PacketType.html">– PacketType</a>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="nav-group-name">
|
||||
<a class="nav-group-name-link" href="Typealiases.html">Type Aliases</a>
|
||||
<ul class="nav-group-tasks">
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="Typealiases.html#/s:8SocketIO11AckCallbacka">AckCallback</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="Typealiases.html#/s:8SocketIO14NormalCallbacka">NormalCallback</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="Typealiases.html#/s:8SocketIO4Posta">Post</a>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
<article class="main-content">
|
||||
|
||||
<section class="section">
|
||||
<div class="section-content top-matter">
|
||||
|
||||
<h1 id='upgrading-from-v15-to-v16' class='heading'>Upgrading from v15 to v16</h1>
|
||||
|
||||
<p>This guide will help you navigate the changes that were introduced in v16.</p>
|
||||
<h2 id='objective-c-is-no-longer-supported-you-must-now-use-swift' class='heading'>Objective-c is no longer supported. You must now use Swift.</h2>
|
||||
<h2 id='client-supports-multiple-socket-io-versions' class='heading'>Client supports multiple socket.io versions</h2>
|
||||
|
||||
<p>The client now supports socket.io 3 servers. This is mostly a transparent change, however if your sever
|
||||
is socket.io 2, you must send <code>.version(.two)</code> as an option to the manager.</p>
|
||||
<pre class="highlight swift"><code><span class="kt">SocketManager</span><span class="p">(</span><span class="nv">socketURL</span><span class="p">:</span> <span class="kt">URL</span><span class="p">(</span><span class="nv">string</span><span class="p">:</span><span class="s">"http://localhost:8087/"</span><span class="p">)</span><span class="o">!</span><span class="p">,</span> <span class="nv">config</span><span class="p">:</span> <span class="p">[</span><span class="o">.</span><span class="nf">version</span><span class="p">(</span><span class="o">.</span><span class="n">two</span><span class="p">)])</span>
|
||||
</code></pre>
|
||||
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
||||
</article>
|
||||
</div>
|
||||
<section class="footer">
|
||||
<p>© 2021 <a class="link" href="https://github.com/socketio/socket.io-client-swift" target="_blank" rel="external">Erik</a>. All rights reserved. (Last updated: 2021-02-01)</p>
|
||||
<p>Generated by <a class="link" href="https://github.com/realm/jazzy" target="_blank" rel="external">jazzy ♪♫ v0.13.6</a>, a <a class="link" href="https://realm.io" target="_blank" rel="external">Realm</a> project.</p>
|
||||
</section>
|
||||
</body>
|
||||
</div>
|
||||
</html>
|
||||
526
docs/Classes.html
Normal file
526
docs/Classes.html
Normal file
@ -0,0 +1,526 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>Classes Reference</title>
|
||||
<link rel="stylesheet" type="text/css" href="css/jazzy.css" />
|
||||
<link rel="stylesheet" type="text/css" href="css/highlight.css" />
|
||||
<meta charset="utf-8">
|
||||
<script src="js/jquery.min.js" defer></script>
|
||||
<script src="js/jazzy.js" defer></script>
|
||||
|
||||
<script src="js/lunr.min.js" defer></script>
|
||||
<script src="js/typeahead.jquery.js" defer></script>
|
||||
<script src="js/jazzy.search.js" defer></script>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<a name="//apple_ref/swift/Section/Classes" class="dashAnchor"></a>
|
||||
|
||||
<a title="Classes Reference"></a>
|
||||
|
||||
<header class="header">
|
||||
<p class="header-col header-col--primary">
|
||||
<a class="header-link" href="index.html">
|
||||
SocketIO 16.0.0 Docs
|
||||
</a>
|
||||
(100% documented)
|
||||
</p>
|
||||
|
||||
<p class="header-col--secondary">
|
||||
<form role="search" action="search.json">
|
||||
<input type="text" placeholder="Search documentation" data-typeahead>
|
||||
</form>
|
||||
</p>
|
||||
|
||||
|
||||
</header>
|
||||
|
||||
<p class="breadcrumbs">
|
||||
<a class="breadcrumb" href="index.html">SocketIO Reference</a>
|
||||
<img class="carat" src="img/carat.png" />
|
||||
Classes Reference
|
||||
</p>
|
||||
|
||||
<div class="content-wrapper">
|
||||
<nav class="navigation">
|
||||
<ul class="nav-groups">
|
||||
<li class="nav-group-name">
|
||||
<a class="nav-group-name-link" href="Guides.html">Guides</a>
|
||||
<ul class="nav-group-tasks">
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="12to13.html">12to13</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="15to16.html">15to16</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="faq.html">FAQ</a>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="nav-group-name">
|
||||
<a class="nav-group-name-link" href="Classes.html">Classes</a>
|
||||
<ul class="nav-group-tasks">
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="Classes/OnAckCallback.html">OnAckCallback</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="Classes/SocketAckEmitter.html">SocketAckEmitter</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="Classes/SocketAnyEvent.html">SocketAnyEvent</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="Classes/SocketEngine.html">SocketEngine</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="Classes/SocketIOClient.html">SocketIOClient</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="Classes/SocketManager.html">SocketManager</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="Classes/SocketRawAckView.html">SocketRawAckView</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="Classes/SocketRawView.html">SocketRawView</a>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="nav-group-name">
|
||||
<a class="nav-group-name-link" href="Enums.html">Enumerations</a>
|
||||
<ul class="nav-group-tasks">
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="Enums/SocketAckStatus.html">SocketAckStatus</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="Enums/SocketClientEvent.html">SocketClientEvent</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="Enums/SocketEnginePacketType.html">SocketEnginePacketType</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="Enums/SocketIOClientOption.html">SocketIOClientOption</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="Enums/SocketIOStatus.html">SocketIOStatus</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="Enums/SocketIOVersion.html">SocketIOVersion</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="Enums/SocketParsableError.html">SocketParsableError</a>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="nav-group-name">
|
||||
<a class="nav-group-name-link" href="Extensions.html">Extensions</a>
|
||||
<ul class="nav-group-tasks">
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="Extensions.html#/s:Sa">Array</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="Extensions.html#/s:Sb">Bool</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="Extensions.html#/s:10Foundation4DataV">Data</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="Extensions.html#/s:SD">Dictionary</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="Extensions.html#/s:Sd">Double</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="Extensions.html#/s:Si">Int</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="Extensions.html#/c:objc(cs)NSArray">NSArray</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="Extensions.html#/c:objc(cs)NSData">NSData</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="Extensions.html#/c:objc(cs)NSDictionary">NSDictionary</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="Extensions.html#/c:objc(cs)NSNull">NSNull</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="Extensions.html#/c:objc(cs)NSString">NSString</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="Extensions.html#/s:SS">String</a>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="nav-group-name">
|
||||
<a class="nav-group-name-link" href="Protocols.html">Protocols</a>
|
||||
<ul class="nav-group-tasks">
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="Protocols/ConfigSettable.html">ConfigSettable</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="Protocols/SocketData.html">SocketData</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="Protocols/SocketDataBufferable.html">SocketDataBufferable</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="Protocols/SocketEngineClient.html">SocketEngineClient</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="Protocols/SocketEnginePollable.html">SocketEnginePollable</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="Protocols/SocketEngineSpec.html">SocketEngineSpec</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="Protocols/SocketEngineWebsocket.html">SocketEngineWebsocket</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="Protocols/SocketIOClientSpec.html">SocketIOClientSpec</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="Protocols/SocketLogger.html">SocketLogger</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="Protocols/SocketManagerSpec.html">SocketManagerSpec</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="Protocols/SocketParsable.html">SocketParsable</a>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="nav-group-name">
|
||||
<a class="nav-group-name-link" href="Structs.html">Structures</a>
|
||||
<ul class="nav-group-tasks">
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="Structs/SocketEventHandler.html">SocketEventHandler</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="Structs/SocketIOClientConfiguration.html">SocketIOClientConfiguration</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="Structs/SocketPacket.html">SocketPacket</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="Structs/SocketPacket/PacketType.html">– PacketType</a>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="nav-group-name">
|
||||
<a class="nav-group-name-link" href="Typealiases.html">Type Aliases</a>
|
||||
<ul class="nav-group-tasks">
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="Typealiases.html#/s:8SocketIO11AckCallbacka">AckCallback</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="Typealiases.html#/s:8SocketIO14NormalCallbacka">NormalCallback</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="Typealiases.html#/s:8SocketIO4Posta">Post</a>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
<article class="main-content">
|
||||
|
||||
<section class="section">
|
||||
<div class="section-content top-matter">
|
||||
<h1>Classes</h1>
|
||||
<p>The following classes are available globally.</p>
|
||||
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="section">
|
||||
<div class="section-content">
|
||||
<div class="task-group">
|
||||
<ul class="item-container">
|
||||
<li class="item">
|
||||
<div>
|
||||
<code>
|
||||
<a name="/c:@M@SocketIO@objc(cs)SocketAckEmitter"></a>
|
||||
<a name="//apple_ref/swift/Class/SocketAckEmitter" class="dashAnchor"></a>
|
||||
<a class="token" href="#/c:@M@SocketIO@objc(cs)SocketAckEmitter">SocketAckEmitter</a>
|
||||
</code>
|
||||
</div>
|
||||
<div class="height-container">
|
||||
<div class="pointer-container"></div>
|
||||
<section class="section">
|
||||
<div class="pointer"></div>
|
||||
<div class="abstract">
|
||||
<p>A class that represents a waiting ack call.</p>
|
||||
|
||||
<p><strong>NOTE</strong>: You should not store this beyond the life of the event handler.</p>
|
||||
|
||||
<a href="Classes/SocketAckEmitter.html" class="slightly-smaller">See more</a>
|
||||
</div>
|
||||
<div class="declaration">
|
||||
<h4>Declaration</h4>
|
||||
<div class="language">
|
||||
<p class="aside-title">Swift</p>
|
||||
<pre class="highlight swift"><code><span class="kd">public</span> <span class="kd">final</span> <span class="kd">class</span> <span class="kt">SocketAckEmitter</span> <span class="p">:</span> <span class="kt">NSObject</span></code></pre>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</li>
|
||||
<li class="item">
|
||||
<div>
|
||||
<code>
|
||||
<a name="/c:@M@SocketIO@objc(cs)OnAckCallback"></a>
|
||||
<a name="//apple_ref/swift/Class/OnAckCallback" class="dashAnchor"></a>
|
||||
<a class="token" href="#/c:@M@SocketIO@objc(cs)OnAckCallback">OnAckCallback</a>
|
||||
</code>
|
||||
</div>
|
||||
<div class="height-container">
|
||||
<div class="pointer-container"></div>
|
||||
<section class="section">
|
||||
<div class="pointer"></div>
|
||||
<div class="abstract">
|
||||
<p>A class that represents an emit that will request an ack that has not yet been sent.
|
||||
Call <code>timingOut(after:callback:)</code> to complete the emit
|
||||
Example:</p>
|
||||
<pre class="highlight swift"><code><span class="n">socket</span><span class="o">.</span><span class="nf">emitWithAck</span><span class="p">(</span><span class="s">"myEvent"</span><span class="p">)</span><span class="o">.</span><span class="nf">timingOut</span><span class="p">(</span><span class="nv">after</span><span class="p">:</span> <span class="mi">1</span><span class="p">)</span> <span class="p">{</span><span class="n">data</span> <span class="k">in</span>
|
||||
<span class="o">...</span>
|
||||
<span class="p">}</span>
|
||||
</code></pre>
|
||||
|
||||
<a href="Classes/OnAckCallback.html" class="slightly-smaller">See more</a>
|
||||
</div>
|
||||
<div class="declaration">
|
||||
<h4>Declaration</h4>
|
||||
<div class="language">
|
||||
<p class="aside-title">Swift</p>
|
||||
<pre class="highlight swift"><code><span class="kd">public</span> <span class="kd">final</span> <span class="kd">class</span> <span class="kt">OnAckCallback</span> <span class="p">:</span> <span class="kt">NSObject</span></code></pre>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</li>
|
||||
<li class="item">
|
||||
<div>
|
||||
<code>
|
||||
<a name="/c:@M@SocketIO@objc(cs)SocketAnyEvent"></a>
|
||||
<a name="//apple_ref/swift/Class/SocketAnyEvent" class="dashAnchor"></a>
|
||||
<a class="token" href="#/c:@M@SocketIO@objc(cs)SocketAnyEvent">SocketAnyEvent</a>
|
||||
</code>
|
||||
</div>
|
||||
<div class="height-container">
|
||||
<div class="pointer-container"></div>
|
||||
<section class="section">
|
||||
<div class="pointer"></div>
|
||||
<div class="abstract">
|
||||
<p>Represents some event that was received.</p>
|
||||
|
||||
<a href="Classes/SocketAnyEvent.html" class="slightly-smaller">See more</a>
|
||||
</div>
|
||||
<div class="declaration">
|
||||
<h4>Declaration</h4>
|
||||
<div class="language">
|
||||
<p class="aside-title">Swift</p>
|
||||
<pre class="highlight swift"><code><span class="kd">public</span> <span class="kd">final</span> <span class="kd">class</span> <span class="kt">SocketAnyEvent</span> <span class="p">:</span> <span class="kt">NSObject</span></code></pre>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</li>
|
||||
<li class="item">
|
||||
<div>
|
||||
<code>
|
||||
<a name="/c:@M@SocketIO@objc(cs)SocketIOClient"></a>
|
||||
<a name="//apple_ref/swift/Class/SocketIOClient" class="dashAnchor"></a>
|
||||
<a class="token" href="#/c:@M@SocketIO@objc(cs)SocketIOClient">SocketIOClient</a>
|
||||
</code>
|
||||
</div>
|
||||
<div class="height-container">
|
||||
<div class="pointer-container"></div>
|
||||
<section class="section">
|
||||
<div class="pointer"></div>
|
||||
<div class="abstract">
|
||||
<p>Represents a socket.io-client.</p>
|
||||
|
||||
<p>Clients are created through a <code><a href="Classes/SocketManager.html">SocketManager</a></code>, which owns the <code><a href="Protocols/SocketEngineSpec.html">SocketEngineSpec</a></code> that controls the connection to the server.</p>
|
||||
|
||||
<p>For example:</p>
|
||||
<pre class="highlight swift"><code><span class="c1">// Create a socket for the /swift namespace</span>
|
||||
<span class="k">let</span> <span class="nv">socket</span> <span class="o">=</span> <span class="n">manager</span><span class="o">.</span><span class="nf">socket</span><span class="p">(</span><span class="nv">forNamespace</span><span class="p">:</span> <span class="s">"/swift"</span><span class="p">)</span>
|
||||
|
||||
<span class="c1">// Add some handlers and connect</span>
|
||||
</code></pre>
|
||||
|
||||
<p><strong>NOTE</strong>: The client is not thread/queue safe, all interaction with the socket should be done on the <code>manager.handleQueue</code></p>
|
||||
|
||||
<a href="Classes/SocketIOClient.html" class="slightly-smaller">See more</a>
|
||||
</div>
|
||||
<div class="declaration">
|
||||
<h4>Declaration</h4>
|
||||
<div class="language">
|
||||
<p class="aside-title">Swift</p>
|
||||
<pre class="highlight swift"><code><span class="kd">open</span> <span class="kd">class</span> <span class="kt">SocketIOClient</span> <span class="p">:</span> <span class="kt">NSObject</span><span class="p">,</span> <span class="kt"><a href="Protocols/SocketIOClientSpec.html">SocketIOClientSpec</a></span></code></pre>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</li>
|
||||
<li class="item">
|
||||
<div>
|
||||
<code>
|
||||
<a name="/c:@M@SocketIO@objc(cs)SocketRawView"></a>
|
||||
<a name="//apple_ref/swift/Class/SocketRawView" class="dashAnchor"></a>
|
||||
<a class="token" href="#/c:@M@SocketIO@objc(cs)SocketRawView">SocketRawView</a>
|
||||
</code>
|
||||
</div>
|
||||
<div class="height-container">
|
||||
<div class="pointer-container"></div>
|
||||
<section class="section">
|
||||
<div class="pointer"></div>
|
||||
<div class="abstract">
|
||||
<p>Class that gives a backwards compatible way to cause an emit not to recursively check for Data objects.</p>
|
||||
|
||||
<p>Usage:</p>
|
||||
<pre class="highlight swift"><code><span class="n">socket</span><span class="o">.</span><span class="n">rawEmitView</span><span class="o">.</span><span class="nf">emit</span><span class="p">(</span><span class="s">"myEvent"</span><span class="p">,</span> <span class="n">myObject</span><span class="p">)</span>
|
||||
</code></pre>
|
||||
|
||||
<a href="Classes/SocketRawView.html" class="slightly-smaller">See more</a>
|
||||
</div>
|
||||
<div class="declaration">
|
||||
<h4>Declaration</h4>
|
||||
<div class="language">
|
||||
<p class="aside-title">Swift</p>
|
||||
<pre class="highlight swift"><code><span class="kd">public</span> <span class="kd">final</span> <span class="kd">class</span> <span class="kt">SocketRawView</span> <span class="p">:</span> <span class="kt">NSObject</span></code></pre>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</li>
|
||||
<li class="item">
|
||||
<div>
|
||||
<code>
|
||||
<a name="/c:@M@SocketIO@objc(cs)SocketRawAckView"></a>
|
||||
<a name="//apple_ref/swift/Class/SocketRawAckView" class="dashAnchor"></a>
|
||||
<a class="token" href="#/c:@M@SocketIO@objc(cs)SocketRawAckView">SocketRawAckView</a>
|
||||
</code>
|
||||
</div>
|
||||
<div class="height-container">
|
||||
<div class="pointer-container"></div>
|
||||
<section class="section">
|
||||
<div class="pointer"></div>
|
||||
<div class="abstract">
|
||||
<p>Class that gives a backwards compatible way to cause an emit not to recursively check for Data objects.</p>
|
||||
|
||||
<p>Usage:</p>
|
||||
<pre class="highlight swift"><code><span class="n">ack</span><span class="o">.</span><span class="n">rawEmitView</span><span class="o">.</span><span class="nf">with</span><span class="p">(</span><span class="n">myObject</span><span class="p">)</span>
|
||||
</code></pre>
|
||||
|
||||
<a href="Classes/SocketRawAckView.html" class="slightly-smaller">See more</a>
|
||||
</div>
|
||||
<div class="declaration">
|
||||
<h4>Declaration</h4>
|
||||
<div class="language">
|
||||
<p class="aside-title">Swift</p>
|
||||
<pre class="highlight swift"><code><span class="kd">public</span> <span class="kd">final</span> <span class="kd">class</span> <span class="kt">SocketRawAckView</span> <span class="p">:</span> <span class="kt">NSObject</span></code></pre>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</li>
|
||||
<li class="item">
|
||||
<div>
|
||||
<code>
|
||||
<a name="/c:@M@SocketIO@objc(cs)SocketEngine"></a>
|
||||
<a name="//apple_ref/swift/Class/SocketEngine" class="dashAnchor"></a>
|
||||
<a class="token" href="#/c:@M@SocketIO@objc(cs)SocketEngine">SocketEngine</a>
|
||||
</code>
|
||||
</div>
|
||||
<div class="height-container">
|
||||
<div class="pointer-container"></div>
|
||||
<section class="section">
|
||||
<div class="pointer"></div>
|
||||
<div class="abstract">
|
||||
<p>The class that handles the engine.io protocol and transports.
|
||||
See <code><a href="Protocols/SocketEnginePollable.html">SocketEnginePollable</a></code> and <code><a href="Protocols/SocketEngineWebsocket.html">SocketEngineWebsocket</a></code> for transport specific methods.</p>
|
||||
|
||||
<a href="Classes/SocketEngine.html" class="slightly-smaller">See more</a>
|
||||
</div>
|
||||
<div class="declaration">
|
||||
<h4>Declaration</h4>
|
||||
<div class="language">
|
||||
<p class="aside-title">Swift</p>
|
||||
<pre class="highlight swift"><code><span class="kd">open</span> <span class="kd">class</span> <span class="kt">SocketEngine</span><span class="p">:</span>
|
||||
<span class="kt">NSObject</span><span class="p">,</span> <span class="kt">WebSocketDelegate</span><span class="p">,</span> <span class="kt">URLSessionDelegate</span><span class="p">,</span> <span class="kt"><a href="Protocols/SocketEnginePollable.html">SocketEnginePollable</a></span><span class="p">,</span> <span class="kt"><a href="Protocols/SocketEngineWebsocket.html">SocketEngineWebsocket</a></span><span class="p">,</span> <span class="kt"><a href="Protocols/ConfigSettable.html">ConfigSettable</a></span></code></pre>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</li>
|
||||
<li class="item">
|
||||
<div>
|
||||
<code>
|
||||
<a name="/c:@M@SocketIO@objc(cs)SocketManager"></a>
|
||||
<a name="//apple_ref/swift/Class/SocketManager" class="dashAnchor"></a>
|
||||
<a class="token" href="#/c:@M@SocketIO@objc(cs)SocketManager">SocketManager</a>
|
||||
</code>
|
||||
</div>
|
||||
<div class="height-container">
|
||||
<div class="pointer-container"></div>
|
||||
<section class="section">
|
||||
<div class="pointer"></div>
|
||||
<div class="abstract">
|
||||
<p>A manager for a socket.io connection.</p>
|
||||
|
||||
<p>A <code>SocketManager</code> is responsible for multiplexing multiple namespaces through a single <code><a href="Protocols/SocketEngineSpec.html">SocketEngineSpec</a></code>.</p>
|
||||
|
||||
<p>Example:</p>
|
||||
<pre class="highlight swift"><code><span class="k">let</span> <span class="nv">manager</span> <span class="o">=</span> <span class="kt">SocketManager</span><span class="p">(</span><span class="nv">socketURL</span><span class="p">:</span> <span class="kt">URL</span><span class="p">(</span><span class="nv">string</span><span class="p">:</span><span class="s">"http://localhost:8080/"</span><span class="p">)</span><span class="o">!</span><span class="p">)</span>
|
||||
<span class="k">let</span> <span class="nv">defaultNamespaceSocket</span> <span class="o">=</span> <span class="n">manager</span><span class="o">.</span><span class="n">defaultSocket</span>
|
||||
<span class="k">let</span> <span class="nv">swiftSocket</span> <span class="o">=</span> <span class="n">manager</span><span class="o">.</span><span class="nf">socket</span><span class="p">(</span><span class="nv">forNamespace</span><span class="p">:</span> <span class="s">"/swift"</span><span class="p">)</span>
|
||||
|
||||
<span class="c1">// defaultNamespaceSocket and swiftSocket both share a single connection to the server</span>
|
||||
</code></pre>
|
||||
|
||||
<p>Sockets created through the manager are retained by the manager. So at the very least, a single strong reference
|
||||
to the manager must be maintained to keep sockets alive.</p>
|
||||
|
||||
<p>To disconnect a socket and remove it from the manager, either call <code><a href="Classes/SocketIOClient.html#/s:8SocketIO0A8IOClientC10disconnectyyF">SocketIOClient.disconnect()</a></code> on the socket,
|
||||
or call one of the <code>disconnectSocket</code> methods on this class.</p>
|
||||
|
||||
<p><strong>NOTE</strong>: The manager is not thread/queue safe, all interaction with the manager should be done on the <code>handleQueue</code></p>
|
||||
|
||||
<a href="Classes/SocketManager.html" class="slightly-smaller">See more</a>
|
||||
</div>
|
||||
<div class="declaration">
|
||||
<h4>Declaration</h4>
|
||||
<div class="language">
|
||||
<p class="aside-title">Swift</p>
|
||||
<pre class="highlight swift"><code><span class="kd">open</span> <span class="kd">class</span> <span class="kt">SocketManager</span> <span class="p">:</span> <span class="kt">NSObject</span><span class="p">,</span> <span class="kt"><a href="Protocols/SocketManagerSpec.html">SocketManagerSpec</a></span><span class="p">,</span> <span class="kt"><a href="Protocols/SocketParsable.html">SocketParsable</a></span><span class="p">,</span> <span class="kt"><a href="Protocols/SocketDataBufferable.html">SocketDataBufferable</a></span><span class="p">,</span> <span class="kt"><a href="Protocols/ConfigSettable.html">ConfigSettable</a></span></code></pre>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
</article>
|
||||
</div>
|
||||
<section class="footer">
|
||||
<p>© 2021 <a class="link" href="https://github.com/socketio/socket.io-client-swift" target="_blank" rel="external">Erik</a>. All rights reserved. (Last updated: 2021-02-01)</p>
|
||||
<p>Generated by <a class="link" href="https://github.com/realm/jazzy" target="_blank" rel="external">jazzy ♪♫ v0.13.6</a>, a <a class="link" href="https://realm.io" target="_blank" rel="external">Realm</a> project.</p>
|
||||
</section>
|
||||
</body>
|
||||
</div>
|
||||
</html>
|
||||
337
docs/Classes/OnAckCallback.html
Normal file
337
docs/Classes/OnAckCallback.html
Normal file
@ -0,0 +1,337 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>OnAckCallback Class Reference</title>
|
||||
<link rel="stylesheet" type="text/css" href="../css/jazzy.css" />
|
||||
<link rel="stylesheet" type="text/css" href="../css/highlight.css" />
|
||||
<meta charset="utf-8">
|
||||
<script src="../js/jquery.min.js" defer></script>
|
||||
<script src="../js/jazzy.js" defer></script>
|
||||
|
||||
<script src="../js/lunr.min.js" defer></script>
|
||||
<script src="../js/typeahead.jquery.js" defer></script>
|
||||
<script src="../js/jazzy.search.js" defer></script>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<a name="//apple_ref/swift/Class/OnAckCallback" class="dashAnchor"></a>
|
||||
|
||||
<a title="OnAckCallback Class Reference"></a>
|
||||
|
||||
<header class="header">
|
||||
<p class="header-col header-col--primary">
|
||||
<a class="header-link" href="../index.html">
|
||||
SocketIO 16.0.0 Docs
|
||||
</a>
|
||||
(100% documented)
|
||||
</p>
|
||||
|
||||
<p class="header-col--secondary">
|
||||
<form role="search" action="../search.json">
|
||||
<input type="text" placeholder="Search documentation" data-typeahead>
|
||||
</form>
|
||||
</p>
|
||||
|
||||
|
||||
</header>
|
||||
|
||||
<p class="breadcrumbs">
|
||||
<a class="breadcrumb" href="../index.html">SocketIO Reference</a>
|
||||
<img class="carat" src="../img/carat.png" />
|
||||
OnAckCallback Class Reference
|
||||
</p>
|
||||
|
||||
<div class="content-wrapper">
|
||||
<nav class="navigation">
|
||||
<ul class="nav-groups">
|
||||
<li class="nav-group-name">
|
||||
<a class="nav-group-name-link" href="../Guides.html">Guides</a>
|
||||
<ul class="nav-group-tasks">
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../12to13.html">12to13</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../15to16.html">15to16</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../faq.html">FAQ</a>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="nav-group-name">
|
||||
<a class="nav-group-name-link" href="../Classes.html">Classes</a>
|
||||
<ul class="nav-group-tasks">
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Classes/OnAckCallback.html">OnAckCallback</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Classes/SocketAckEmitter.html">SocketAckEmitter</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Classes/SocketAnyEvent.html">SocketAnyEvent</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Classes/SocketEngine.html">SocketEngine</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Classes/SocketIOClient.html">SocketIOClient</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Classes/SocketManager.html">SocketManager</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Classes/SocketRawAckView.html">SocketRawAckView</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Classes/SocketRawView.html">SocketRawView</a>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="nav-group-name">
|
||||
<a class="nav-group-name-link" href="../Enums.html">Enumerations</a>
|
||||
<ul class="nav-group-tasks">
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Enums/SocketAckStatus.html">SocketAckStatus</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Enums/SocketClientEvent.html">SocketClientEvent</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Enums/SocketEnginePacketType.html">SocketEnginePacketType</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Enums/SocketIOClientOption.html">SocketIOClientOption</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Enums/SocketIOStatus.html">SocketIOStatus</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Enums/SocketIOVersion.html">SocketIOVersion</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Enums/SocketParsableError.html">SocketParsableError</a>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="nav-group-name">
|
||||
<a class="nav-group-name-link" href="../Extensions.html">Extensions</a>
|
||||
<ul class="nav-group-tasks">
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Extensions.html#/s:Sa">Array</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Extensions.html#/s:Sb">Bool</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Extensions.html#/s:10Foundation4DataV">Data</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Extensions.html#/s:SD">Dictionary</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Extensions.html#/s:Sd">Double</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Extensions.html#/s:Si">Int</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Extensions.html#/c:objc(cs)NSArray">NSArray</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Extensions.html#/c:objc(cs)NSData">NSData</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Extensions.html#/c:objc(cs)NSDictionary">NSDictionary</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Extensions.html#/c:objc(cs)NSNull">NSNull</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Extensions.html#/c:objc(cs)NSString">NSString</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Extensions.html#/s:SS">String</a>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="nav-group-name">
|
||||
<a class="nav-group-name-link" href="../Protocols.html">Protocols</a>
|
||||
<ul class="nav-group-tasks">
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Protocols/ConfigSettable.html">ConfigSettable</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Protocols/SocketData.html">SocketData</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Protocols/SocketDataBufferable.html">SocketDataBufferable</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Protocols/SocketEngineClient.html">SocketEngineClient</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Protocols/SocketEnginePollable.html">SocketEnginePollable</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Protocols/SocketEngineSpec.html">SocketEngineSpec</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Protocols/SocketEngineWebsocket.html">SocketEngineWebsocket</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Protocols/SocketIOClientSpec.html">SocketIOClientSpec</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Protocols/SocketLogger.html">SocketLogger</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Protocols/SocketManagerSpec.html">SocketManagerSpec</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Protocols/SocketParsable.html">SocketParsable</a>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="nav-group-name">
|
||||
<a class="nav-group-name-link" href="../Structs.html">Structures</a>
|
||||
<ul class="nav-group-tasks">
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Structs/SocketEventHandler.html">SocketEventHandler</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Structs/SocketIOClientConfiguration.html">SocketIOClientConfiguration</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Structs/SocketPacket.html">SocketPacket</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Structs/SocketPacket/PacketType.html">– PacketType</a>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="nav-group-name">
|
||||
<a class="nav-group-name-link" href="../Typealiases.html">Type Aliases</a>
|
||||
<ul class="nav-group-tasks">
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Typealiases.html#/s:8SocketIO11AckCallbacka">AckCallback</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Typealiases.html#/s:8SocketIO14NormalCallbacka">NormalCallback</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Typealiases.html#/s:8SocketIO4Posta">Post</a>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
<article class="main-content">
|
||||
|
||||
<section class="section">
|
||||
<div class="section-content top-matter">
|
||||
<h1>OnAckCallback</h1>
|
||||
<div class="declaration">
|
||||
<div class="language">
|
||||
|
||||
<pre class="highlight swift"><code><span class="kd">public</span> <span class="kd">final</span> <span class="kd">class</span> <span class="kt">OnAckCallback</span> <span class="p">:</span> <span class="kt">NSObject</span></code></pre>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<p>A class that represents an emit that will request an ack that has not yet been sent.
|
||||
Call <code>timingOut(after:callback:)</code> to complete the emit
|
||||
Example:</p>
|
||||
<pre class="highlight swift"><code><span class="n">socket</span><span class="o">.</span><span class="nf">emitWithAck</span><span class="p">(</span><span class="s">"myEvent"</span><span class="p">)</span><span class="o">.</span><span class="nf">timingOut</span><span class="p">(</span><span class="nv">after</span><span class="p">:</span> <span class="mi">1</span><span class="p">)</span> <span class="p">{</span><span class="n">data</span> <span class="k">in</span>
|
||||
<span class="o">...</span>
|
||||
<span class="p">}</span>
|
||||
</code></pre>
|
||||
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="section">
|
||||
<div class="section-content">
|
||||
<div class="task-group">
|
||||
<div class="task-name-container">
|
||||
<a name="/Methods"></a>
|
||||
<a name="//apple_ref/swift/Section/Methods" class="dashAnchor"></a>
|
||||
<div class="section-name-container">
|
||||
<a class="section-name-link" href="#/Methods"></a>
|
||||
<h3 class="section-name"><p>Methods</p>
|
||||
</h3>
|
||||
</div>
|
||||
</div>
|
||||
<ul class="item-container">
|
||||
<li class="item">
|
||||
<div>
|
||||
<code>
|
||||
<a name="/c:@M@SocketIO@objc(cs)OnAckCallback(im)timingOutAfter:callback:"></a>
|
||||
<a name="//apple_ref/swift/Method/timingOut(after:callback:)" class="dashAnchor"></a>
|
||||
<a class="token" href="#/c:@M@SocketIO@objc(cs)OnAckCallback(im)timingOutAfter:callback:">timingOut(after:<wbr>callback:<wbr>)</a>
|
||||
</code>
|
||||
</div>
|
||||
<div class="height-container">
|
||||
<div class="pointer-container"></div>
|
||||
<section class="section">
|
||||
<div class="pointer"></div>
|
||||
<div class="abstract">
|
||||
<p>Completes an emitWithAck. If this isn’t called, the emit never happens.</p>
|
||||
|
||||
</div>
|
||||
<div class="declaration">
|
||||
<h4>Declaration</h4>
|
||||
<div class="language">
|
||||
<p class="aside-title">Swift</p>
|
||||
<pre class="highlight swift"><code><span class="kd">@objc</span>
|
||||
<span class="kd">public</span> <span class="kd">func</span> <span class="nf">timingOut</span><span class="p">(</span><span class="n">after</span> <span class="nv">seconds</span><span class="p">:</span> <span class="kt">Double</span><span class="p">,</span> <span class="nv">callback</span><span class="p">:</span> <span class="kd">@escaping</span> <span class="kt"><a href="../Typealiases.html#/s:8SocketIO11AckCallbacka">AckCallback</a></span><span class="p">)</span></code></pre>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<h4>Parameters</h4>
|
||||
<table class="graybox">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>
|
||||
<code>
|
||||
<em>seconds</em>
|
||||
</code>
|
||||
</td>
|
||||
<td>
|
||||
<div>
|
||||
<p>The number of seconds before this emit times out if an ack hasn’t been received.</p>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<code>
|
||||
<em>callback</em>
|
||||
</code>
|
||||
</td>
|
||||
<td>
|
||||
<div>
|
||||
<p>The callback called when an ack is received, or when a timeout happens.
|
||||
To check for timeout, use <code><a href="../Enums/SocketAckStatus.html">SocketAckStatus</a></code>‘s <code>noAck</code> case.</p>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
</article>
|
||||
</div>
|
||||
<section class="footer">
|
||||
<p>© 2021 <a class="link" href="https://github.com/socketio/socket.io-client-swift" target="_blank" rel="external">Erik</a>. All rights reserved. (Last updated: 2021-02-01)</p>
|
||||
<p>Generated by <a class="link" href="https://github.com/realm/jazzy" target="_blank" rel="external">jazzy ♪♫ v0.13.6</a>, a <a class="link" href="https://realm.io" target="_blank" rel="external">Realm</a> project.</p>
|
||||
</section>
|
||||
</body>
|
||||
</div>
|
||||
</html>
|
||||
436
docs/Classes/SSLSecurity.html
Normal file
436
docs/Classes/SSLSecurity.html
Normal file
@ -0,0 +1,436 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>SSLSecurity Class Reference</title>
|
||||
<link rel="stylesheet" type="text/css" href="../css/jazzy.css" />
|
||||
<link rel="stylesheet" type="text/css" href="../css/highlight.css" />
|
||||
<meta charset="utf-8">
|
||||
<script src="../js/jquery.min.js" defer></script>
|
||||
<script src="../js/jazzy.js" defer></script>
|
||||
|
||||
<script src="../js/lunr.min.js" defer></script>
|
||||
<script src="../js/typeahead.jquery.js" defer></script>
|
||||
<script src="../js/jazzy.search.js" defer></script>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<a name="//apple_ref/swift/Class/SSLSecurity" class="dashAnchor"></a>
|
||||
|
||||
<a title="SSLSecurity Class Reference"></a>
|
||||
|
||||
<header class="header">
|
||||
<p class="header-col header-col--primary">
|
||||
<a class="header-link" href="../index.html">
|
||||
SocketIO Docs
|
||||
</a>
|
||||
(100% documented)
|
||||
</p>
|
||||
|
||||
<p class="header-col--secondary">
|
||||
<form role="search" action="../search.json">
|
||||
<input type="text" placeholder="Search documentation" data-typeahead>
|
||||
</form>
|
||||
</p>
|
||||
|
||||
|
||||
</header>
|
||||
|
||||
<p class="breadcrumbs">
|
||||
<a class="breadcrumb" href="../index.html">SocketIO Reference</a>
|
||||
<img class="carat" src="../img/carat.png" />
|
||||
SSLSecurity Class Reference
|
||||
</p>
|
||||
|
||||
<div class="content-wrapper">
|
||||
<nav class="navigation">
|
||||
<ul class="nav-groups">
|
||||
<li class="nav-group-name">
|
||||
<a class="nav-group-name-link" href="../Guides.html">Guides</a>
|
||||
<ul class="nav-group-tasks">
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../12to13.html">12to13</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../faq.html">FAQ</a>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="nav-group-name">
|
||||
<a class="nav-group-name-link" href="../Classes.html">Classes</a>
|
||||
<ul class="nav-group-tasks">
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Classes/OnAckCallback.html">OnAckCallback</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Classes/SSLSecurity.html">SSLSecurity</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Classes/SocketAckEmitter.html">SocketAckEmitter</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Classes/SocketAnyEvent.html">SocketAnyEvent</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Classes/SocketEngine.html">SocketEngine</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Classes/SocketIOClient.html">SocketIOClient</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Classes/SocketManager.html">SocketManager</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Classes/SocketRawAckView.html">SocketRawAckView</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Classes/SocketRawView.html">SocketRawView</a>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="nav-group-name">
|
||||
<a class="nav-group-name-link" href="../Enums.html">Enumerations</a>
|
||||
<ul class="nav-group-tasks">
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Enums/SocketAckStatus.html">SocketAckStatus</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Enums/SocketClientEvent.html">SocketClientEvent</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Enums/SocketEnginePacketType.html">SocketEnginePacketType</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Enums/SocketIOClientOption.html">SocketIOClientOption</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Enums/SocketIOStatus.html">SocketIOStatus</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Enums/SocketParsableError.html">SocketParsableError</a>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="nav-group-name">
|
||||
<a class="nav-group-name-link" href="../Protocols.html">Protocols</a>
|
||||
<ul class="nav-group-tasks">
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Protocols/ConfigSettable.html">ConfigSettable</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Protocols/SocketData.html">SocketData</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Protocols/SocketDataBufferable.html">SocketDataBufferable</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Protocols/SocketEngineClient.html">SocketEngineClient</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Protocols/SocketEnginePollable.html">SocketEnginePollable</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Protocols/SocketEngineSpec.html">SocketEngineSpec</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Protocols/SocketEngineWebsocket.html">SocketEngineWebsocket</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Protocols/SocketIOClientSpec.html">SocketIOClientSpec</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Protocols/SocketLogger.html">SocketLogger</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Protocols/SocketManagerSpec.html">SocketManagerSpec</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Protocols/SocketParsable.html">SocketParsable</a>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="nav-group-name">
|
||||
<a class="nav-group-name-link" href="../Structs.html">Structures</a>
|
||||
<ul class="nav-group-tasks">
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Structs/SocketEventHandler.html">SocketEventHandler</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Structs/SocketIOClientConfiguration.html">SocketIOClientConfiguration</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Structs/SocketPacket.html">SocketPacket</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Structs/SocketPacket/PacketType.html">– PacketType</a>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="nav-group-name">
|
||||
<a class="nav-group-name-link" href="../Typealiases.html">Type Aliases</a>
|
||||
<ul class="nav-group-tasks">
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Typealiases.html#/s:8SocketIO11AckCallbacka">AckCallback</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Typealiases.html#/s:8SocketIO14NormalCallbacka">NormalCallback</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Typealiases.html#/s:8SocketIO4Posta">Post</a>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
<article class="main-content">
|
||||
|
||||
<section class="section">
|
||||
<div class="section-content">
|
||||
<h1>SSLSecurity</h1>
|
||||
<div class="declaration">
|
||||
<div class="language">
|
||||
<pre class="highlight swift"><code><span class="kd">open</span> <span class="kd">class</span> <span class="kt">SSLSecurity</span> <span class="p">:</span> <span class="kt">NSObject</span></code></pre>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<p>A wrapper around Starscream’s SSLSecurity that provides a minimal Objective-C interface.</p>
|
||||
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="section">
|
||||
<div class="section-content">
|
||||
<div class="task-group">
|
||||
<div class="task-name-container">
|
||||
<a name="/Properties"></a>
|
||||
<a name="//apple_ref/swift/Section/Properties" class="dashAnchor"></a>
|
||||
<a href="#/Properties">
|
||||
<h3 class="section-name">Properties</h3>
|
||||
</a>
|
||||
</div>
|
||||
<ul class="item-container">
|
||||
<li class="item">
|
||||
<div>
|
||||
<code>
|
||||
<a name="/s:8SocketIO11SSLSecurityC8security10StarscreamABCvp"></a>
|
||||
<a name="//apple_ref/swift/Property/security" class="dashAnchor"></a>
|
||||
<a class="token" href="#/s:8SocketIO11SSLSecurityC8security10StarscreamABCvp">security</a>
|
||||
</code>
|
||||
</div>
|
||||
<div class="height-container">
|
||||
<div class="pointer-container"></div>
|
||||
<section class="section">
|
||||
<div class="pointer"></div>
|
||||
<div class="abstract">
|
||||
<p>The internal Starscream SSLSecurity.</p>
|
||||
|
||||
</div>
|
||||
<div class="declaration">
|
||||
<h4>Declaration</h4>
|
||||
<div class="language">
|
||||
<p class="aside-title">Swift</p>
|
||||
<pre class="highlight swift"><code><span class="kd">public</span> <span class="k">let</span> <span class="nv">security</span><span class="p">:</span> <span class="kt">Starscream</span><span class="o">.</span><span class="kt">SSLSecurity</span></code></pre>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="task-group">
|
||||
<div class="task-name-container">
|
||||
<a name="/Methods"></a>
|
||||
<a name="//apple_ref/swift/Section/Methods" class="dashAnchor"></a>
|
||||
<a href="#/Methods">
|
||||
<h3 class="section-name">Methods</h3>
|
||||
</a>
|
||||
</div>
|
||||
<ul class="item-container">
|
||||
<li class="item">
|
||||
<div>
|
||||
<code>
|
||||
<a name="/c:@M@SocketIO@objc(cs)SSLSecurity(im)initWithUsePublicKeys:"></a>
|
||||
<a name="//apple_ref/swift/Method/init(usePublicKeys:)" class="dashAnchor"></a>
|
||||
<a class="token" href="#/c:@M@SocketIO@objc(cs)SSLSecurity(im)initWithUsePublicKeys:">init(usePublicKeys:)</a>
|
||||
</code>
|
||||
</div>
|
||||
<div class="height-container">
|
||||
<div class="pointer-container"></div>
|
||||
<section class="section">
|
||||
<div class="pointer"></div>
|
||||
<div class="abstract">
|
||||
<p>Creates a new SSLSecurity that specifies whether to use publicKeys or certificates should be used for SSL
|
||||
pinning validation</p>
|
||||
|
||||
</div>
|
||||
<div class="declaration">
|
||||
<h4>Declaration</h4>
|
||||
<div class="language">
|
||||
<p class="aside-title">Swift</p>
|
||||
<pre class="highlight swift"><code><span class="kd">@objc</span>
|
||||
<span class="kd">public</span> <span class="n">convenience</span> <span class="nf">init</span><span class="p">(</span><span class="nv">usePublicKeys</span><span class="p">:</span> <span class="kt">Bool</span> <span class="o">=</span> <span class="kc">true</span><span class="p">)</span></code></pre>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<h4>Parameters</h4>
|
||||
<table class="graybox">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>
|
||||
<code>
|
||||
<em>usePublicKeys</em>
|
||||
</code>
|
||||
</td>
|
||||
<td>
|
||||
<div>
|
||||
<p>is to specific if the publicKeys or certificates should be used for SSL pinning
|
||||
validation</p>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</li>
|
||||
<li class="item">
|
||||
<div>
|
||||
<code>
|
||||
<a name="/s:8SocketIO11SSLSecurityC5certs13usePublicKeysACSay10Starscream7SSLCertCG_Sbtcfc"></a>
|
||||
<a name="//apple_ref/swift/Method/init(certs:usePublicKeys:)" class="dashAnchor"></a>
|
||||
<a class="token" href="#/s:8SocketIO11SSLSecurityC5certs13usePublicKeysACSay10Starscream7SSLCertCG_Sbtcfc">init(certs:usePublicKeys:)</a>
|
||||
</code>
|
||||
</div>
|
||||
<div class="height-container">
|
||||
<div class="pointer-container"></div>
|
||||
<section class="section">
|
||||
<div class="pointer"></div>
|
||||
<div class="abstract">
|
||||
<p>Designated init</p>
|
||||
|
||||
</div>
|
||||
<div class="declaration">
|
||||
<h4>Declaration</h4>
|
||||
<div class="language">
|
||||
<p class="aside-title">Swift</p>
|
||||
<pre class="highlight swift"><code><span class="kd">public</span> <span class="n">convenience</span> <span class="nf">init</span><span class="p">(</span><span class="nv">certs</span><span class="p">:</span> <span class="p">[</span><span class="kt">SSLCert</span><span class="p">],</span> <span class="nv">usePublicKeys</span><span class="p">:</span> <span class="kt">Bool</span><span class="p">)</span></code></pre>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<h4>Parameters</h4>
|
||||
<table class="graybox">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>
|
||||
<code>
|
||||
<em>certs</em>
|
||||
</code>
|
||||
</td>
|
||||
<td>
|
||||
<div>
|
||||
<p>is the certificates or public keys to use</p>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<code>
|
||||
<em>usePublicKeys</em>
|
||||
</code>
|
||||
</td>
|
||||
<td>
|
||||
<div>
|
||||
<p>is to specific if the publicKeys or certificates should be used for SSL pinning
|
||||
validation</p>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div>
|
||||
<h4>Return Value</h4>
|
||||
<p>a representation security object to be used with</p>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</li>
|
||||
<li class="item">
|
||||
<div>
|
||||
<code>
|
||||
<a name="/s:8SocketIO11SSLSecurityC7isValid_6domainSbSo11SecTrustRefa_SSSgtF"></a>
|
||||
<a name="//apple_ref/swift/Method/isValid(_:domain:)" class="dashAnchor"></a>
|
||||
<a class="token" href="#/s:8SocketIO11SSLSecurityC7isValid_6domainSbSo11SecTrustRefa_SSSgtF">isValid(_:domain:)</a>
|
||||
</code>
|
||||
</div>
|
||||
<div class="height-container">
|
||||
<div class="pointer-container"></div>
|
||||
<section class="section">
|
||||
<div class="pointer"></div>
|
||||
<div class="abstract">
|
||||
<p>Returns whether or not the given trust is valid.</p>
|
||||
|
||||
</div>
|
||||
<div class="declaration">
|
||||
<h4>Declaration</h4>
|
||||
<div class="language">
|
||||
<p class="aside-title">Swift</p>
|
||||
<pre class="highlight swift"><code><span class="kd">public</span> <span class="kd">func</span> <span class="nf">isValid</span><span class="p">(</span><span class="n">_</span> <span class="nv">trust</span><span class="p">:</span> <span class="kt">SecTrust</span><span class="p">,</span> <span class="nv">domain</span><span class="p">:</span> <span class="kt">String</span><span class="p">?)</span> <span class="o">-></span> <span class="kt">Bool</span></code></pre>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<h4>Parameters</h4>
|
||||
<table class="graybox">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>
|
||||
<code>
|
||||
<em>trust</em>
|
||||
</code>
|
||||
</td>
|
||||
<td>
|
||||
<div>
|
||||
<p>The trust to validate.</p>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<code>
|
||||
<em>domain</em>
|
||||
</code>
|
||||
</td>
|
||||
<td>
|
||||
<div>
|
||||
<p>The CN domain to validate.</p>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div>
|
||||
<h4>Return Value</h4>
|
||||
<p>Whether or not this is valid.</p>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
</article>
|
||||
</div>
|
||||
<section class="footer">
|
||||
<p>© 2019 <a class="link" href="https://github.com/socketio/socket.io-client-swift" target="_blank" rel="external">Erik</a>. All rights reserved. (Last updated: 2019-05-28)</p>
|
||||
<p>Generated by <a class="link" href="https://github.com/realm/jazzy" target="_blank" rel="external">jazzy ♪♫ v0.9.4</a>, a <a class="link" href="https://realm.io" target="_blank" rel="external">Realm</a> project.</p>
|
||||
</section>
|
||||
</body>
|
||||
</div>
|
||||
</html>
|
||||
518
docs/Classes/SocketAckEmitter.html
Normal file
518
docs/Classes/SocketAckEmitter.html
Normal file
@ -0,0 +1,518 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>SocketAckEmitter Class Reference</title>
|
||||
<link rel="stylesheet" type="text/css" href="../css/jazzy.css" />
|
||||
<link rel="stylesheet" type="text/css" href="../css/highlight.css" />
|
||||
<meta charset="utf-8">
|
||||
<script src="../js/jquery.min.js" defer></script>
|
||||
<script src="../js/jazzy.js" defer></script>
|
||||
|
||||
<script src="../js/lunr.min.js" defer></script>
|
||||
<script src="../js/typeahead.jquery.js" defer></script>
|
||||
<script src="../js/jazzy.search.js" defer></script>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<a name="//apple_ref/swift/Class/SocketAckEmitter" class="dashAnchor"></a>
|
||||
|
||||
<a title="SocketAckEmitter Class Reference"></a>
|
||||
|
||||
<header class="header">
|
||||
<p class="header-col header-col--primary">
|
||||
<a class="header-link" href="../index.html">
|
||||
SocketIO 16.0.0 Docs
|
||||
</a>
|
||||
(100% documented)
|
||||
</p>
|
||||
|
||||
<p class="header-col--secondary">
|
||||
<form role="search" action="../search.json">
|
||||
<input type="text" placeholder="Search documentation" data-typeahead>
|
||||
</form>
|
||||
</p>
|
||||
|
||||
|
||||
</header>
|
||||
|
||||
<p class="breadcrumbs">
|
||||
<a class="breadcrumb" href="../index.html">SocketIO Reference</a>
|
||||
<img class="carat" src="../img/carat.png" />
|
||||
SocketAckEmitter Class Reference
|
||||
</p>
|
||||
|
||||
<div class="content-wrapper">
|
||||
<nav class="navigation">
|
||||
<ul class="nav-groups">
|
||||
<li class="nav-group-name">
|
||||
<a class="nav-group-name-link" href="../Guides.html">Guides</a>
|
||||
<ul class="nav-group-tasks">
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../12to13.html">12to13</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../15to16.html">15to16</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../faq.html">FAQ</a>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="nav-group-name">
|
||||
<a class="nav-group-name-link" href="../Classes.html">Classes</a>
|
||||
<ul class="nav-group-tasks">
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Classes/OnAckCallback.html">OnAckCallback</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Classes/SocketAckEmitter.html">SocketAckEmitter</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Classes/SocketAnyEvent.html">SocketAnyEvent</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Classes/SocketEngine.html">SocketEngine</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Classes/SocketIOClient.html">SocketIOClient</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Classes/SocketManager.html">SocketManager</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Classes/SocketRawAckView.html">SocketRawAckView</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Classes/SocketRawView.html">SocketRawView</a>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="nav-group-name">
|
||||
<a class="nav-group-name-link" href="../Enums.html">Enumerations</a>
|
||||
<ul class="nav-group-tasks">
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Enums/SocketAckStatus.html">SocketAckStatus</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Enums/SocketClientEvent.html">SocketClientEvent</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Enums/SocketEnginePacketType.html">SocketEnginePacketType</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Enums/SocketIOClientOption.html">SocketIOClientOption</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Enums/SocketIOStatus.html">SocketIOStatus</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Enums/SocketIOVersion.html">SocketIOVersion</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Enums/SocketParsableError.html">SocketParsableError</a>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="nav-group-name">
|
||||
<a class="nav-group-name-link" href="../Extensions.html">Extensions</a>
|
||||
<ul class="nav-group-tasks">
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Extensions.html#/s:Sa">Array</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Extensions.html#/s:Sb">Bool</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Extensions.html#/s:10Foundation4DataV">Data</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Extensions.html#/s:SD">Dictionary</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Extensions.html#/s:Sd">Double</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Extensions.html#/s:Si">Int</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Extensions.html#/c:objc(cs)NSArray">NSArray</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Extensions.html#/c:objc(cs)NSData">NSData</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Extensions.html#/c:objc(cs)NSDictionary">NSDictionary</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Extensions.html#/c:objc(cs)NSNull">NSNull</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Extensions.html#/c:objc(cs)NSString">NSString</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Extensions.html#/s:SS">String</a>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="nav-group-name">
|
||||
<a class="nav-group-name-link" href="../Protocols.html">Protocols</a>
|
||||
<ul class="nav-group-tasks">
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Protocols/ConfigSettable.html">ConfigSettable</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Protocols/SocketData.html">SocketData</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Protocols/SocketDataBufferable.html">SocketDataBufferable</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Protocols/SocketEngineClient.html">SocketEngineClient</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Protocols/SocketEnginePollable.html">SocketEnginePollable</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Protocols/SocketEngineSpec.html">SocketEngineSpec</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Protocols/SocketEngineWebsocket.html">SocketEngineWebsocket</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Protocols/SocketIOClientSpec.html">SocketIOClientSpec</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Protocols/SocketLogger.html">SocketLogger</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Protocols/SocketManagerSpec.html">SocketManagerSpec</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Protocols/SocketParsable.html">SocketParsable</a>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="nav-group-name">
|
||||
<a class="nav-group-name-link" href="../Structs.html">Structures</a>
|
||||
<ul class="nav-group-tasks">
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Structs/SocketEventHandler.html">SocketEventHandler</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Structs/SocketIOClientConfiguration.html">SocketIOClientConfiguration</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Structs/SocketPacket.html">SocketPacket</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Structs/SocketPacket/PacketType.html">– PacketType</a>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="nav-group-name">
|
||||
<a class="nav-group-name-link" href="../Typealiases.html">Type Aliases</a>
|
||||
<ul class="nav-group-tasks">
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Typealiases.html#/s:8SocketIO11AckCallbacka">AckCallback</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Typealiases.html#/s:8SocketIO14NormalCallbacka">NormalCallback</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Typealiases.html#/s:8SocketIO4Posta">Post</a>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
<article class="main-content">
|
||||
|
||||
<section class="section">
|
||||
<div class="section-content top-matter">
|
||||
<h1>SocketAckEmitter</h1>
|
||||
<div class="declaration">
|
||||
<div class="language">
|
||||
|
||||
<pre class="highlight swift"><code><span class="kd">public</span> <span class="kd">final</span> <span class="kd">class</span> <span class="kt">SocketAckEmitter</span> <span class="p">:</span> <span class="kt">NSObject</span></code></pre>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<p>A class that represents a waiting ack call.</p>
|
||||
|
||||
<p><strong>NOTE</strong>: You should not store this beyond the life of the event handler.</p>
|
||||
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="section">
|
||||
<div class="section-content">
|
||||
<div class="task-group">
|
||||
<ul class="item-container">
|
||||
<li class="item">
|
||||
<div>
|
||||
<code>
|
||||
<a name="/c:@M@SocketIO@objc(cs)SocketAckEmitter(py)rawEmitView"></a>
|
||||
<a name="//apple_ref/swift/Property/rawEmitView" class="dashAnchor"></a>
|
||||
<a class="token" href="#/c:@M@SocketIO@objc(cs)SocketAckEmitter(py)rawEmitView">rawEmitView</a>
|
||||
</code>
|
||||
</div>
|
||||
<div class="height-container">
|
||||
<div class="pointer-container"></div>
|
||||
<section class="section">
|
||||
<div class="pointer"></div>
|
||||
<div class="abstract">
|
||||
<p>A view into this emitter where emits do not check for binary data.</p>
|
||||
|
||||
<p>Usage:</p>
|
||||
<pre class="highlight swift"><code><span class="n">ack</span><span class="o">.</span><span class="n">rawEmitView</span><span class="o">.</span><span class="nf">with</span><span class="p">(</span><span class="n">myObject</span><span class="p">)</span>
|
||||
</code></pre>
|
||||
|
||||
<p><strong>NOTE</strong>: It is not safe to hold on to this view beyond the life of the socket.</p>
|
||||
|
||||
</div>
|
||||
<div class="declaration">
|
||||
<h4>Declaration</h4>
|
||||
<div class="language">
|
||||
<p class="aside-title">Swift</p>
|
||||
<pre class="highlight swift"><code><span class="kd">@objc</span>
|
||||
<span class="kd">public</span> <span class="kd">private(set)</span> <span class="kd">lazy</span> <span class="k">var</span> <span class="nv">rawEmitView</span><span class="p">:</span> <span class="kt"><a href="../Classes/SocketRawAckView.html">SocketRawAckView</a></span> <span class="p">{</span> <span class="k">get</span> <span class="k">set</span> <span class="p">}</span></code></pre>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="task-group">
|
||||
<div class="task-name-container">
|
||||
<a name="/Properties"></a>
|
||||
<a name="//apple_ref/swift/Section/Properties" class="dashAnchor"></a>
|
||||
<div class="section-name-container">
|
||||
<a class="section-name-link" href="#/Properties"></a>
|
||||
<h3 class="section-name"><p>Properties</p>
|
||||
</h3>
|
||||
</div>
|
||||
</div>
|
||||
<ul class="item-container">
|
||||
<li class="item">
|
||||
<div>
|
||||
<code>
|
||||
<a name="/s:8SocketIO0A10AckEmitterC8expectedSbvp"></a>
|
||||
<a name="//apple_ref/swift/Property/expected" class="dashAnchor"></a>
|
||||
<a class="token" href="#/s:8SocketIO0A10AckEmitterC8expectedSbvp">expected</a>
|
||||
</code>
|
||||
</div>
|
||||
<div class="height-container">
|
||||
<div class="pointer-container"></div>
|
||||
<section class="section">
|
||||
<div class="pointer"></div>
|
||||
<div class="abstract">
|
||||
<p>If true, this handler is expecting to be acked. Call <code>with(_: SocketData...)</code> to ack.</p>
|
||||
|
||||
</div>
|
||||
<div class="declaration">
|
||||
<h4>Declaration</h4>
|
||||
<div class="language">
|
||||
<p class="aside-title">Swift</p>
|
||||
<pre class="highlight swift"><code><span class="kd">public</span> <span class="k">var</span> <span class="nv">expected</span><span class="p">:</span> <span class="kt">Bool</span> <span class="p">{</span> <span class="k">get</span> <span class="p">}</span></code></pre>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="task-group">
|
||||
<div class="task-name-container">
|
||||
<a name="/Initializers"></a>
|
||||
<a name="//apple_ref/swift/Section/Initializers" class="dashAnchor"></a>
|
||||
<div class="section-name-container">
|
||||
<a class="section-name-link" href="#/Initializers"></a>
|
||||
<h3 class="section-name"><p>Initializers</p>
|
||||
</h3>
|
||||
</div>
|
||||
</div>
|
||||
<ul class="item-container">
|
||||
<li class="item">
|
||||
<div>
|
||||
<code>
|
||||
<a name="/s:8SocketIO0A10AckEmitterC6socket6ackNumAcA0A8IOClientC_Sitcfc"></a>
|
||||
<a name="//apple_ref/swift/Method/init(socket:ackNum:)" class="dashAnchor"></a>
|
||||
<a class="token" href="#/s:8SocketIO0A10AckEmitterC6socket6ackNumAcA0A8IOClientC_Sitcfc">init(socket:<wbr>ackNum:<wbr>)</a>
|
||||
</code>
|
||||
</div>
|
||||
<div class="height-container">
|
||||
<div class="pointer-container"></div>
|
||||
<section class="section">
|
||||
<div class="pointer"></div>
|
||||
<div class="abstract">
|
||||
<p>Creates a new <code>SocketAckEmitter</code>.</p>
|
||||
|
||||
</div>
|
||||
<div class="declaration">
|
||||
<h4>Declaration</h4>
|
||||
<div class="language">
|
||||
<p class="aside-title">Swift</p>
|
||||
<pre class="highlight swift"><code><span class="kd">public</span> <span class="nf">init</span><span class="p">(</span><span class="nv">socket</span><span class="p">:</span> <span class="kt"><a href="../Classes/SocketIOClient.html">SocketIOClient</a></span><span class="p">,</span> <span class="nv">ackNum</span><span class="p">:</span> <span class="kt">Int</span><span class="p">)</span></code></pre>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<h4>Parameters</h4>
|
||||
<table class="graybox">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>
|
||||
<code>
|
||||
<em>socket</em>
|
||||
</code>
|
||||
</td>
|
||||
<td>
|
||||
<div>
|
||||
<p>The socket for this emitter.</p>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<code>
|
||||
<em>ackNum</em>
|
||||
</code>
|
||||
</td>
|
||||
<td>
|
||||
<div>
|
||||
<p>The ack number for this emitter.</p>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="task-group">
|
||||
<div class="task-name-container">
|
||||
<a name="/Methods"></a>
|
||||
<a name="//apple_ref/swift/Section/Methods" class="dashAnchor"></a>
|
||||
<div class="section-name-container">
|
||||
<a class="section-name-link" href="#/Methods"></a>
|
||||
<h3 class="section-name"><p>Methods</p>
|
||||
</h3>
|
||||
</div>
|
||||
</div>
|
||||
<ul class="item-container">
|
||||
<li class="item">
|
||||
<div>
|
||||
<code>
|
||||
<a name="/s:8SocketIO0A10AckEmitterC4withyyAA0A4Data_pd_tF"></a>
|
||||
<a name="//apple_ref/swift/Method/with(_:)" class="dashAnchor"></a>
|
||||
<a class="token" href="#/s:8SocketIO0A10AckEmitterC4withyyAA0A4Data_pd_tF">with(_:<wbr>)</a>
|
||||
</code>
|
||||
</div>
|
||||
<div class="height-container">
|
||||
<div class="pointer-container"></div>
|
||||
<section class="section">
|
||||
<div class="pointer"></div>
|
||||
<div class="abstract">
|
||||
<p>Call to ack receiving this event.</p>
|
||||
|
||||
<p>If an error occurs trying to transform <code>items</code> into their socket representation, a <code><a href="../Enums/SocketClientEvent.html#/s:8SocketIO0A11ClientEventO5erroryA2CmF">SocketClientEvent.error</a></code>
|
||||
will be emitted. The structure of the error data is <code>[ackNum, items, theError]</code></p>
|
||||
|
||||
</div>
|
||||
<div class="declaration">
|
||||
<h4>Declaration</h4>
|
||||
<div class="language">
|
||||
<p class="aside-title">Swift</p>
|
||||
<pre class="highlight swift"><code><span class="kd">public</span> <span class="kd">func</span> <span class="nf">with</span><span class="p">(</span><span class="n">_</span> <span class="nv">items</span><span class="p">:</span> <span class="kt"><a href="../Protocols/SocketData.html">SocketData</a></span><span class="o">...</span><span class="p">)</span></code></pre>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<h4>Parameters</h4>
|
||||
<table class="graybox">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>
|
||||
<code>
|
||||
<em>items</em>
|
||||
</code>
|
||||
</td>
|
||||
<td>
|
||||
<div>
|
||||
<p>A variable number of items to send when acking.</p>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</li>
|
||||
<li class="item">
|
||||
<div>
|
||||
<code>
|
||||
<a name="/c:@M@SocketIO@objc(cs)SocketAckEmitter(im)with:"></a>
|
||||
<a name="//apple_ref/swift/Method/with(_:)" class="dashAnchor"></a>
|
||||
<a class="token" href="#/c:@M@SocketIO@objc(cs)SocketAckEmitter(im)with:">with(_:<wbr>)</a>
|
||||
</code>
|
||||
</div>
|
||||
<div class="height-container">
|
||||
<div class="pointer-container"></div>
|
||||
<section class="section">
|
||||
<div class="pointer"></div>
|
||||
<div class="abstract">
|
||||
<p>Call to ack receiving this event.</p>
|
||||
|
||||
</div>
|
||||
<div class="declaration">
|
||||
<h4>Declaration</h4>
|
||||
<div class="language">
|
||||
<p class="aside-title">Swift</p>
|
||||
<pre class="highlight swift"><code><span class="kd">@objc</span>
|
||||
<span class="kd">public</span> <span class="kd">func</span> <span class="nf">with</span><span class="p">(</span><span class="n">_</span> <span class="nv">items</span><span class="p">:</span> <span class="p">[</span><span class="kt">Any</span><span class="p">])</span></code></pre>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<h4>Parameters</h4>
|
||||
<table class="graybox">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>
|
||||
<code>
|
||||
<em>items</em>
|
||||
</code>
|
||||
</td>
|
||||
<td>
|
||||
<div>
|
||||
<p>An array of items to send when acking. Use <code>[]</code> to send nothing.</p>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
</article>
|
||||
</div>
|
||||
<section class="footer">
|
||||
<p>© 2021 <a class="link" href="https://github.com/socketio/socket.io-client-swift" target="_blank" rel="external">Erik</a>. All rights reserved. (Last updated: 2021-02-01)</p>
|
||||
<p>Generated by <a class="link" href="https://github.com/realm/jazzy" target="_blank" rel="external">jazzy ♪♫ v0.13.6</a>, a <a class="link" href="https://realm.io" target="_blank" rel="external">Realm</a> project.</p>
|
||||
</section>
|
||||
</body>
|
||||
</div>
|
||||
</html>
|
||||
354
docs/Classes/SocketAnyEvent.html
Normal file
354
docs/Classes/SocketAnyEvent.html
Normal file
@ -0,0 +1,354 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>SocketAnyEvent Class Reference</title>
|
||||
<link rel="stylesheet" type="text/css" href="../css/jazzy.css" />
|
||||
<link rel="stylesheet" type="text/css" href="../css/highlight.css" />
|
||||
<meta charset="utf-8">
|
||||
<script src="../js/jquery.min.js" defer></script>
|
||||
<script src="../js/jazzy.js" defer></script>
|
||||
|
||||
<script src="../js/lunr.min.js" defer></script>
|
||||
<script src="../js/typeahead.jquery.js" defer></script>
|
||||
<script src="../js/jazzy.search.js" defer></script>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<a name="//apple_ref/swift/Class/SocketAnyEvent" class="dashAnchor"></a>
|
||||
|
||||
<a title="SocketAnyEvent Class Reference"></a>
|
||||
|
||||
<header class="header">
|
||||
<p class="header-col header-col--primary">
|
||||
<a class="header-link" href="../index.html">
|
||||
SocketIO 16.0.0 Docs
|
||||
</a>
|
||||
(100% documented)
|
||||
</p>
|
||||
|
||||
<p class="header-col--secondary">
|
||||
<form role="search" action="../search.json">
|
||||
<input type="text" placeholder="Search documentation" data-typeahead>
|
||||
</form>
|
||||
</p>
|
||||
|
||||
|
||||
</header>
|
||||
|
||||
<p class="breadcrumbs">
|
||||
<a class="breadcrumb" href="../index.html">SocketIO Reference</a>
|
||||
<img class="carat" src="../img/carat.png" />
|
||||
SocketAnyEvent Class Reference
|
||||
</p>
|
||||
|
||||
<div class="content-wrapper">
|
||||
<nav class="navigation">
|
||||
<ul class="nav-groups">
|
||||
<li class="nav-group-name">
|
||||
<a class="nav-group-name-link" href="../Guides.html">Guides</a>
|
||||
<ul class="nav-group-tasks">
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../12to13.html">12to13</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../15to16.html">15to16</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../faq.html">FAQ</a>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="nav-group-name">
|
||||
<a class="nav-group-name-link" href="../Classes.html">Classes</a>
|
||||
<ul class="nav-group-tasks">
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Classes/OnAckCallback.html">OnAckCallback</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Classes/SocketAckEmitter.html">SocketAckEmitter</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Classes/SocketAnyEvent.html">SocketAnyEvent</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Classes/SocketEngine.html">SocketEngine</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Classes/SocketIOClient.html">SocketIOClient</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Classes/SocketManager.html">SocketManager</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Classes/SocketRawAckView.html">SocketRawAckView</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Classes/SocketRawView.html">SocketRawView</a>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="nav-group-name">
|
||||
<a class="nav-group-name-link" href="../Enums.html">Enumerations</a>
|
||||
<ul class="nav-group-tasks">
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Enums/SocketAckStatus.html">SocketAckStatus</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Enums/SocketClientEvent.html">SocketClientEvent</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Enums/SocketEnginePacketType.html">SocketEnginePacketType</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Enums/SocketIOClientOption.html">SocketIOClientOption</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Enums/SocketIOStatus.html">SocketIOStatus</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Enums/SocketIOVersion.html">SocketIOVersion</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Enums/SocketParsableError.html">SocketParsableError</a>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="nav-group-name">
|
||||
<a class="nav-group-name-link" href="../Extensions.html">Extensions</a>
|
||||
<ul class="nav-group-tasks">
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Extensions.html#/s:Sa">Array</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Extensions.html#/s:Sb">Bool</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Extensions.html#/s:10Foundation4DataV">Data</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Extensions.html#/s:SD">Dictionary</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Extensions.html#/s:Sd">Double</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Extensions.html#/s:Si">Int</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Extensions.html#/c:objc(cs)NSArray">NSArray</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Extensions.html#/c:objc(cs)NSData">NSData</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Extensions.html#/c:objc(cs)NSDictionary">NSDictionary</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Extensions.html#/c:objc(cs)NSNull">NSNull</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Extensions.html#/c:objc(cs)NSString">NSString</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Extensions.html#/s:SS">String</a>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="nav-group-name">
|
||||
<a class="nav-group-name-link" href="../Protocols.html">Protocols</a>
|
||||
<ul class="nav-group-tasks">
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Protocols/ConfigSettable.html">ConfigSettable</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Protocols/SocketData.html">SocketData</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Protocols/SocketDataBufferable.html">SocketDataBufferable</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Protocols/SocketEngineClient.html">SocketEngineClient</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Protocols/SocketEnginePollable.html">SocketEnginePollable</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Protocols/SocketEngineSpec.html">SocketEngineSpec</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Protocols/SocketEngineWebsocket.html">SocketEngineWebsocket</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Protocols/SocketIOClientSpec.html">SocketIOClientSpec</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Protocols/SocketLogger.html">SocketLogger</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Protocols/SocketManagerSpec.html">SocketManagerSpec</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Protocols/SocketParsable.html">SocketParsable</a>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="nav-group-name">
|
||||
<a class="nav-group-name-link" href="../Structs.html">Structures</a>
|
||||
<ul class="nav-group-tasks">
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Structs/SocketEventHandler.html">SocketEventHandler</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Structs/SocketIOClientConfiguration.html">SocketIOClientConfiguration</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Structs/SocketPacket.html">SocketPacket</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Structs/SocketPacket/PacketType.html">– PacketType</a>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="nav-group-name">
|
||||
<a class="nav-group-name-link" href="../Typealiases.html">Type Aliases</a>
|
||||
<ul class="nav-group-tasks">
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Typealiases.html#/s:8SocketIO11AckCallbacka">AckCallback</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Typealiases.html#/s:8SocketIO14NormalCallbacka">NormalCallback</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Typealiases.html#/s:8SocketIO4Posta">Post</a>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
<article class="main-content">
|
||||
|
||||
<section class="section">
|
||||
<div class="section-content top-matter">
|
||||
<h1>SocketAnyEvent</h1>
|
||||
<div class="declaration">
|
||||
<div class="language">
|
||||
|
||||
<pre class="highlight swift"><code><span class="kd">public</span> <span class="kd">final</span> <span class="kd">class</span> <span class="kt">SocketAnyEvent</span> <span class="p">:</span> <span class="kt">NSObject</span></code></pre>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<p>Represents some event that was received.</p>
|
||||
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="section">
|
||||
<div class="section-content">
|
||||
<div class="task-group">
|
||||
<div class="task-name-container">
|
||||
<a name="/Properties"></a>
|
||||
<a name="//apple_ref/swift/Section/Properties" class="dashAnchor"></a>
|
||||
<div class="section-name-container">
|
||||
<a class="section-name-link" href="#/Properties"></a>
|
||||
<h3 class="section-name"><p>Properties</p>
|
||||
</h3>
|
||||
</div>
|
||||
</div>
|
||||
<ul class="item-container">
|
||||
<li class="item">
|
||||
<div>
|
||||
<code>
|
||||
<a name="/c:@M@SocketIO@objc(cs)SocketAnyEvent(py)event"></a>
|
||||
<a name="//apple_ref/swift/Property/event" class="dashAnchor"></a>
|
||||
<a class="token" href="#/c:@M@SocketIO@objc(cs)SocketAnyEvent(py)event">event</a>
|
||||
</code>
|
||||
</div>
|
||||
<div class="height-container">
|
||||
<div class="pointer-container"></div>
|
||||
<section class="section">
|
||||
<div class="pointer"></div>
|
||||
<div class="abstract">
|
||||
<p>The event name.</p>
|
||||
|
||||
</div>
|
||||
<div class="declaration">
|
||||
<h4>Declaration</h4>
|
||||
<div class="language">
|
||||
<p class="aside-title">Swift</p>
|
||||
<pre class="highlight swift"><code><span class="kd">@objc</span>
|
||||
<span class="kd">public</span> <span class="k">let</span> <span class="nv">event</span><span class="p">:</span> <span class="kt">String</span></code></pre>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</li>
|
||||
<li class="item">
|
||||
<div>
|
||||
<code>
|
||||
<a name="/c:@M@SocketIO@objc(cs)SocketAnyEvent(py)items"></a>
|
||||
<a name="//apple_ref/swift/Property/items" class="dashAnchor"></a>
|
||||
<a class="token" href="#/c:@M@SocketIO@objc(cs)SocketAnyEvent(py)items">items</a>
|
||||
</code>
|
||||
</div>
|
||||
<div class="height-container">
|
||||
<div class="pointer-container"></div>
|
||||
<section class="section">
|
||||
<div class="pointer"></div>
|
||||
<div class="abstract">
|
||||
<p>The data items for this event.</p>
|
||||
|
||||
</div>
|
||||
<div class="declaration">
|
||||
<h4>Declaration</h4>
|
||||
<div class="language">
|
||||
<p class="aside-title">Swift</p>
|
||||
<pre class="highlight swift"><code><span class="kd">@objc</span>
|
||||
<span class="kd">public</span> <span class="k">let</span> <span class="nv">items</span><span class="p">:</span> <span class="p">[</span><span class="kt">Any</span><span class="p">]?</span></code></pre>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</li>
|
||||
<li class="item">
|
||||
<div>
|
||||
<code>
|
||||
<a name="/c:@M@SocketIO@objc(cs)SocketAnyEvent(py)description"></a>
|
||||
<a name="//apple_ref/swift/Property/description" class="dashAnchor"></a>
|
||||
<a class="token" href="#/c:@M@SocketIO@objc(cs)SocketAnyEvent(py)description">description</a>
|
||||
</code>
|
||||
</div>
|
||||
<div class="height-container">
|
||||
<div class="pointer-container"></div>
|
||||
<section class="section">
|
||||
<div class="pointer"></div>
|
||||
<div class="abstract">
|
||||
<p>The description of this event.</p>
|
||||
|
||||
</div>
|
||||
<div class="declaration">
|
||||
<h4>Declaration</h4>
|
||||
<div class="language">
|
||||
<p class="aside-title">Swift</p>
|
||||
<pre class="highlight swift"><code><span class="k">override</span> <span class="kd">public</span> <span class="k">var</span> <span class="nv">description</span><span class="p">:</span> <span class="kt">String</span> <span class="p">{</span> <span class="k">get</span> <span class="p">}</span></code></pre>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
</article>
|
||||
</div>
|
||||
<section class="footer">
|
||||
<p>© 2021 <a class="link" href="https://github.com/socketio/socket.io-client-swift" target="_blank" rel="external">Erik</a>. All rights reserved. (Last updated: 2021-02-01)</p>
|
||||
<p>Generated by <a class="link" href="https://github.com/realm/jazzy" target="_blank" rel="external">jazzy ♪♫ v0.13.6</a>, a <a class="link" href="https://realm.io" target="_blank" rel="external">Realm</a> project.</p>
|
||||
</section>
|
||||
</body>
|
||||
</div>
|
||||
</html>
|
||||
472
docs/Classes/SocketClientManager.html
Normal file
472
docs/Classes/SocketClientManager.html
Normal file
@ -0,0 +1,472 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>SocketClientManager Class Reference</title>
|
||||
<link rel="stylesheet" type="text/css" href="../css/jazzy.css" />
|
||||
<link rel="stylesheet" type="text/css" href="../css/highlight.css" />
|
||||
<meta charset="utf-8">
|
||||
<script src="../js/jquery.min.js" defer></script>
|
||||
<script src="../js/jazzy.js" defer></script>
|
||||
|
||||
<script src="../js/lunr.min.js" defer></script>
|
||||
<script src="../js/typeahead.jquery.js" defer></script>
|
||||
<script src="../js/jazzy.search.js" defer></script>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<a name="//apple_ref/swift/Class/SocketClientManager" class="dashAnchor"></a>
|
||||
|
||||
<a title="SocketClientManager Class Reference"></a>
|
||||
|
||||
<header class="header">
|
||||
<p class="header-col header-col--primary">
|
||||
<a class="header-link" href="../index.html">
|
||||
SocketIO Docs
|
||||
</a>
|
||||
(100% documented)
|
||||
</p>
|
||||
|
||||
<p class="header-col--secondary">
|
||||
<form role="search" action="../search.json">
|
||||
<input type="text" placeholder="Search documentation" data-typeahead>
|
||||
</form>
|
||||
</p>
|
||||
|
||||
|
||||
</header>
|
||||
|
||||
<p class="breadcrumbs">
|
||||
<a class="breadcrumb" href="../index.html">SocketIO Reference</a>
|
||||
<img class="carat" src="../img/carat.png" />
|
||||
SocketClientManager Class Reference
|
||||
</p>
|
||||
|
||||
<div class="content-wrapper">
|
||||
<nav class="navigation">
|
||||
<ul class="nav-groups">
|
||||
<li class="nav-group-name">
|
||||
<a class="nav-group-name-link" href="../Guides.html">Guides</a>
|
||||
<ul class="nav-group-tasks">
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../faq.html">FAQ</a>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="nav-group-name">
|
||||
<a class="nav-group-name-link" href="../Classes.html">Classes</a>
|
||||
<ul class="nav-group-tasks">
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Classes/OnAckCallback.html">OnAckCallback</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Classes/SSLSecurity.html">SSLSecurity</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Classes/SocketAckEmitter.html">SocketAckEmitter</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Classes/SocketAnyEvent.html">SocketAnyEvent</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Classes/SocketClientManager.html">SocketClientManager</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Classes/SocketEngine.html">SocketEngine</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Classes/SocketIOClient.html">SocketIOClient</a>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="nav-group-name">
|
||||
<a class="nav-group-name-link" href="../Enums.html">Enumerations</a>
|
||||
<ul class="nav-group-tasks">
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Enums/SocketAckStatus.html">SocketAckStatus</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Enums/SocketClientEvent.html">SocketClientEvent</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Enums/SocketEnginePacketType.html">SocketEnginePacketType</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Enums/SocketIOClientOption.html">SocketIOClientOption</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Enums/SocketIOClientStatus.html">SocketIOClientStatus</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Enums/SocketParsableError.html">SocketParsableError</a>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="nav-group-name">
|
||||
<a class="nav-group-name-link" href="../Protocols.html">Protocols</a>
|
||||
<ul class="nav-group-tasks">
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Protocols/SocketData.html">SocketData</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Protocols/SocketEngineClient.html">SocketEngineClient</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Protocols/SocketEnginePollable.html">SocketEnginePollable</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Protocols/SocketEngineSpec.html">SocketEngineSpec</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Protocols/SocketEngineWebsocket.html">SocketEngineWebsocket</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Protocols/SocketIOClientSpec.html">SocketIOClientSpec</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Protocols/SocketLogger.html">SocketLogger</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Protocols/SocketParsable.html">SocketParsable</a>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="nav-group-name">
|
||||
<a class="nav-group-name-link" href="../Structs.html">Structures</a>
|
||||
<ul class="nav-group-tasks">
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Structs/SocketEventHandler.html">SocketEventHandler</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Structs/SocketIOClientConfiguration.html">SocketIOClientConfiguration</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Structs/SocketPacket.html">SocketPacket</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Structs/SocketPacket/PacketType.html">– PacketType</a>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="nav-group-name">
|
||||
<a class="nav-group-name-link" href="../Typealiases.html">Type Aliases</a>
|
||||
<ul class="nav-group-tasks">
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Typealiases.html#/s:8SocketIO11AckCallbacka">AckCallback</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Typealiases.html#/s:8SocketIO14NormalCallbacka">NormalCallback</a>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
<article class="main-content">
|
||||
|
||||
<section class="section">
|
||||
<div class="section-content">
|
||||
<h1>SocketClientManager</h1>
|
||||
<div class="declaration">
|
||||
<div class="language">
|
||||
<pre class="highlight"><code><span class="n">open</span> <span class="kd">class</span> <span class="kt">SocketClientManager</span> <span class="p">:</span> <span class="kt">NSObject</span></code></pre>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<p>Experimental socket manager.</p>
|
||||
|
||||
<p>API subject to change.</p>
|
||||
|
||||
<p>Can be used to persist sockets across ViewControllers.</p>
|
||||
|
||||
<p>Sockets are strongly stored, so be sure to remove them once they are no
|
||||
longer needed.</p>
|
||||
|
||||
<p>Example usage:</p>
|
||||
<pre class="highlight plaintext"><code>let manager = SocketClientManager.sharedManager
|
||||
manager["room1"] = socket1
|
||||
manager["room2"] = socket2
|
||||
manager.removeSocket(socket: socket2)
|
||||
manager["room1"]?.emit("hello")
|
||||
</code></pre>
|
||||
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="section">
|
||||
<div class="section-content">
|
||||
<div class="task-group">
|
||||
<div class="task-name-container">
|
||||
<a name="/Properties."></a>
|
||||
<a name="//apple_ref/swift/Section/Properties." class="dashAnchor"></a>
|
||||
<a href="#/Properties.">
|
||||
<h3 class="section-name">Properties.</h3>
|
||||
</a>
|
||||
</div>
|
||||
<ul class="item-container">
|
||||
<li class="item">
|
||||
<div>
|
||||
<code>
|
||||
<a name="/c:@M@SocketIO@objc(cs)SocketClientManager(cpy)sharedManager"></a>
|
||||
<a name="//apple_ref/swift/Variable/sharedManager" class="dashAnchor"></a>
|
||||
<a class="token" href="#/c:@M@SocketIO@objc(cs)SocketClientManager(cpy)sharedManager">sharedManager</a>
|
||||
</code>
|
||||
</div>
|
||||
<div class="height-container">
|
||||
<div class="pointer-container"></div>
|
||||
<section class="section">
|
||||
<div class="pointer"></div>
|
||||
<div class="abstract">
|
||||
<p>The shared manager.</p>
|
||||
|
||||
</div>
|
||||
<div class="declaration">
|
||||
<h4>Declaration</h4>
|
||||
<div class="language">
|
||||
<p class="aside-title">Swift</p>
|
||||
<pre class="highlight"><code><span class="n">open</span> <span class="kd">static</span> <span class="k">let</span> <span class="nv">sharedManager</span> <span class="o">=</span> <span class="kt">SocketClientManager</span><span class="p">()</span></code></pre>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</li>
|
||||
<li class="item">
|
||||
<div>
|
||||
<code>
|
||||
<a name="/s:8SocketIO0A13ClientManagerC9subscriptAA0A8IOClientCSgSSci"></a>
|
||||
<a name="//apple_ref/swift/Method/subscript(_:)" class="dashAnchor"></a>
|
||||
<a class="token" href="#/s:8SocketIO0A13ClientManagerC9subscriptAA0A8IOClientCSgSSci">subscript(_:)</a>
|
||||
</code>
|
||||
</div>
|
||||
<div class="height-container">
|
||||
<div class="pointer-container"></div>
|
||||
<section class="section">
|
||||
<div class="pointer"></div>
|
||||
<div class="abstract">
|
||||
<p>Gets a socket by its name.</p>
|
||||
|
||||
</div>
|
||||
<div class="declaration">
|
||||
<h4>Declaration</h4>
|
||||
<div class="language">
|
||||
<p class="aside-title">Swift</p>
|
||||
<pre class="highlight"><code><span class="n">open</span> <span class="nf">subscript</span><span class="p">(</span><span class="nv">string</span><span class="p">:</span> <span class="kt">String</span><span class="p">)</span> <span class="o">-></span> <span class="kt"><a href="../Classes/SocketIOClient.html">SocketIOClient</a></span><span class="p">?</span></code></pre>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<h4>Return Value</h4>
|
||||
<p>The socket, if one had the given name.</p>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="task-group">
|
||||
<div class="task-name-container">
|
||||
<a name="/Methods."></a>
|
||||
<a name="//apple_ref/swift/Section/Methods." class="dashAnchor"></a>
|
||||
<a href="#/Methods.">
|
||||
<h3 class="section-name">Methods.</h3>
|
||||
</a>
|
||||
</div>
|
||||
<ul class="item-container">
|
||||
<li class="item">
|
||||
<div>
|
||||
<code>
|
||||
<a name="/c:@M@SocketIO@objc(cs)SocketClientManager(im)addSocket:labeledAs:"></a>
|
||||
<a name="//apple_ref/swift/Method/addSocket(_:labeledAs:)" class="dashAnchor"></a>
|
||||
<a class="token" href="#/c:@M@SocketIO@objc(cs)SocketClientManager(im)addSocket:labeledAs:">addSocket(_:labeledAs:)</a>
|
||||
</code>
|
||||
</div>
|
||||
<div class="height-container">
|
||||
<div class="pointer-container"></div>
|
||||
<section class="section">
|
||||
<div class="pointer"></div>
|
||||
<div class="abstract">
|
||||
<p>Adds a socket.</p>
|
||||
|
||||
</div>
|
||||
<div class="declaration">
|
||||
<h4>Declaration</h4>
|
||||
<div class="language">
|
||||
<p class="aside-title">Swift</p>
|
||||
<pre class="highlight"><code><span class="n">open</span> <span class="kd">func</span> <span class="nf">addSocket</span><span class="p">(</span><span class="n">_</span> <span class="nv">socket</span><span class="p">:</span> <span class="kt"><a href="../Classes/SocketIOClient.html">SocketIOClient</a></span><span class="p">,</span> <span class="n">labeledAs</span> <span class="nv">label</span><span class="p">:</span> <span class="kt">String</span><span class="p">)</span></code></pre>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<h4>Parameters</h4>
|
||||
<table class="graybox">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>
|
||||
<code>
|
||||
<em>socket</em>
|
||||
</code>
|
||||
</td>
|
||||
<td>
|
||||
<div>
|
||||
<p>The socket to add.</p>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<code>
|
||||
<em>labeledAs</em>
|
||||
</code>
|
||||
</td>
|
||||
<td>
|
||||
<div>
|
||||
<p>The label for this socket.</p>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</li>
|
||||
<li class="item">
|
||||
<div>
|
||||
<code>
|
||||
<a name="/c:@M@SocketIO@objc(cs)SocketClientManager(im)removeSocketWithLabel:"></a>
|
||||
<a name="//apple_ref/swift/Method/removeSocket(withLabel:)" class="dashAnchor"></a>
|
||||
<a class="token" href="#/c:@M@SocketIO@objc(cs)SocketClientManager(im)removeSocketWithLabel:">removeSocket(withLabel:)</a>
|
||||
</code>
|
||||
</div>
|
||||
<div class="height-container">
|
||||
<div class="pointer-container"></div>
|
||||
<section class="section">
|
||||
<div class="pointer"></div>
|
||||
<div class="abstract">
|
||||
<p>Removes a socket by a given name.</p>
|
||||
|
||||
</div>
|
||||
<div class="declaration">
|
||||
<h4>Declaration</h4>
|
||||
<div class="language">
|
||||
<p class="aside-title">Swift</p>
|
||||
<pre class="highlight"><code><span class="n">open</span> <span class="kd">func</span> <span class="nf">removeSocket</span><span class="p">(</span><span class="n">withLabel</span> <span class="nv">label</span><span class="p">:</span> <span class="kt">String</span><span class="p">)</span> <span class="o">-></span> <span class="kt"><a href="../Classes/SocketIOClient.html">SocketIOClient</a></span><span class="p">?</span></code></pre>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<h4>Parameters</h4>
|
||||
<table class="graybox">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>
|
||||
<code>
|
||||
<em>withLabel</em>
|
||||
</code>
|
||||
</td>
|
||||
<td>
|
||||
<div>
|
||||
<p>The label of the socket to remove.</p>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div>
|
||||
<h4>Return Value</h4>
|
||||
<p>The socket for the given label, if one was present.</p>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</li>
|
||||
<li class="item">
|
||||
<div>
|
||||
<code>
|
||||
<a name="/c:@M@SocketIO@objc(cs)SocketClientManager(im)removeSocket:"></a>
|
||||
<a name="//apple_ref/swift/Method/removeSocket(_:)" class="dashAnchor"></a>
|
||||
<a class="token" href="#/c:@M@SocketIO@objc(cs)SocketClientManager(im)removeSocket:">removeSocket(_:)</a>
|
||||
</code>
|
||||
</div>
|
||||
<div class="height-container">
|
||||
<div class="pointer-container"></div>
|
||||
<section class="section">
|
||||
<div class="pointer"></div>
|
||||
<div class="abstract">
|
||||
<p>Removes a socket.</p>
|
||||
|
||||
</div>
|
||||
<div class="declaration">
|
||||
<h4>Declaration</h4>
|
||||
<div class="language">
|
||||
<p class="aside-title">Swift</p>
|
||||
<pre class="highlight"><code><span class="n">open</span> <span class="kd">func</span> <span class="nf">removeSocket</span><span class="p">(</span><span class="n">_</span> <span class="nv">socket</span><span class="p">:</span> <span class="kt"><a href="../Classes/SocketIOClient.html">SocketIOClient</a></span><span class="p">)</span> <span class="o">-></span> <span class="kt"><a href="../Classes/SocketIOClient.html">SocketIOClient</a></span><span class="p">?</span></code></pre>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<h4>Parameters</h4>
|
||||
<table class="graybox">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>
|
||||
<code>
|
||||
<em>socket</em>
|
||||
</code>
|
||||
</td>
|
||||
<td>
|
||||
<div>
|
||||
<p>The socket to remove.</p>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div>
|
||||
<h4>Return Value</h4>
|
||||
<p>The socket if it was in the manager.</p>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</li>
|
||||
<li class="item">
|
||||
<div>
|
||||
<code>
|
||||
<a name="/c:@M@SocketIO@objc(cs)SocketClientManager(im)removeSockets"></a>
|
||||
<a name="//apple_ref/swift/Method/removeSockets()" class="dashAnchor"></a>
|
||||
<a class="token" href="#/c:@M@SocketIO@objc(cs)SocketClientManager(im)removeSockets">removeSockets()</a>
|
||||
</code>
|
||||
</div>
|
||||
<div class="height-container">
|
||||
<div class="pointer-container"></div>
|
||||
<section class="section">
|
||||
<div class="pointer"></div>
|
||||
<div class="abstract">
|
||||
<p>Removes all the sockets in the manager.</p>
|
||||
|
||||
</div>
|
||||
<div class="declaration">
|
||||
<h4>Declaration</h4>
|
||||
<div class="language">
|
||||
<p class="aside-title">Swift</p>
|
||||
<pre class="highlight"><code><span class="n">open</span> <span class="kd">func</span> <span class="nf">removeSockets</span><span class="p">()</span></code></pre>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
</article>
|
||||
</div>
|
||||
<section class="footer">
|
||||
<p>© 2017 <a class="link" href="https://github.com/socketio/socket.io-client-swift" target="_blank" rel="external">Erik</a>. All rights reserved. (Last updated: 2017-10-05)</p>
|
||||
<p>Generated by <a class="link" href="https://github.com/realm/jazzy" target="_blank" rel="external">jazzy ♪♫ v0.8.4</a>, a <a class="link" href="http://realm.io" target="_blank" rel="external">Realm</a> project.</p>
|
||||
</section>
|
||||
</body>
|
||||
</div>
|
||||
</html>
|
||||
1640
docs/Classes/SocketEngine.html
Normal file
1640
docs/Classes/SocketEngine.html
Normal file
File diff suppressed because it is too large
Load Diff
1856
docs/Classes/SocketIOClient.html
Normal file
1856
docs/Classes/SocketIOClient.html
Normal file
File diff suppressed because it is too large
Load Diff
1738
docs/Classes/SocketManager.html
Normal file
1738
docs/Classes/SocketManager.html
Normal file
File diff suppressed because it is too large
Load Diff
362
docs/Classes/SocketRawAckView.html
Normal file
362
docs/Classes/SocketRawAckView.html
Normal file
@ -0,0 +1,362 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>SocketRawAckView Class Reference</title>
|
||||
<link rel="stylesheet" type="text/css" href="../css/jazzy.css" />
|
||||
<link rel="stylesheet" type="text/css" href="../css/highlight.css" />
|
||||
<meta charset="utf-8">
|
||||
<script src="../js/jquery.min.js" defer></script>
|
||||
<script src="../js/jazzy.js" defer></script>
|
||||
|
||||
<script src="../js/lunr.min.js" defer></script>
|
||||
<script src="../js/typeahead.jquery.js" defer></script>
|
||||
<script src="../js/jazzy.search.js" defer></script>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<a name="//apple_ref/swift/Class/SocketRawAckView" class="dashAnchor"></a>
|
||||
|
||||
<a title="SocketRawAckView Class Reference"></a>
|
||||
|
||||
<header class="header">
|
||||
<p class="header-col header-col--primary">
|
||||
<a class="header-link" href="../index.html">
|
||||
SocketIO 16.0.0 Docs
|
||||
</a>
|
||||
(100% documented)
|
||||
</p>
|
||||
|
||||
<p class="header-col--secondary">
|
||||
<form role="search" action="../search.json">
|
||||
<input type="text" placeholder="Search documentation" data-typeahead>
|
||||
</form>
|
||||
</p>
|
||||
|
||||
|
||||
</header>
|
||||
|
||||
<p class="breadcrumbs">
|
||||
<a class="breadcrumb" href="../index.html">SocketIO Reference</a>
|
||||
<img class="carat" src="../img/carat.png" />
|
||||
SocketRawAckView Class Reference
|
||||
</p>
|
||||
|
||||
<div class="content-wrapper">
|
||||
<nav class="navigation">
|
||||
<ul class="nav-groups">
|
||||
<li class="nav-group-name">
|
||||
<a class="nav-group-name-link" href="../Guides.html">Guides</a>
|
||||
<ul class="nav-group-tasks">
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../12to13.html">12to13</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../15to16.html">15to16</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../faq.html">FAQ</a>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="nav-group-name">
|
||||
<a class="nav-group-name-link" href="../Classes.html">Classes</a>
|
||||
<ul class="nav-group-tasks">
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Classes/OnAckCallback.html">OnAckCallback</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Classes/SocketAckEmitter.html">SocketAckEmitter</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Classes/SocketAnyEvent.html">SocketAnyEvent</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Classes/SocketEngine.html">SocketEngine</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Classes/SocketIOClient.html">SocketIOClient</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Classes/SocketManager.html">SocketManager</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Classes/SocketRawAckView.html">SocketRawAckView</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Classes/SocketRawView.html">SocketRawView</a>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="nav-group-name">
|
||||
<a class="nav-group-name-link" href="../Enums.html">Enumerations</a>
|
||||
<ul class="nav-group-tasks">
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Enums/SocketAckStatus.html">SocketAckStatus</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Enums/SocketClientEvent.html">SocketClientEvent</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Enums/SocketEnginePacketType.html">SocketEnginePacketType</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Enums/SocketIOClientOption.html">SocketIOClientOption</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Enums/SocketIOStatus.html">SocketIOStatus</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Enums/SocketIOVersion.html">SocketIOVersion</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Enums/SocketParsableError.html">SocketParsableError</a>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="nav-group-name">
|
||||
<a class="nav-group-name-link" href="../Extensions.html">Extensions</a>
|
||||
<ul class="nav-group-tasks">
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Extensions.html#/s:Sa">Array</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Extensions.html#/s:Sb">Bool</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Extensions.html#/s:10Foundation4DataV">Data</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Extensions.html#/s:SD">Dictionary</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Extensions.html#/s:Sd">Double</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Extensions.html#/s:Si">Int</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Extensions.html#/c:objc(cs)NSArray">NSArray</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Extensions.html#/c:objc(cs)NSData">NSData</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Extensions.html#/c:objc(cs)NSDictionary">NSDictionary</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Extensions.html#/c:objc(cs)NSNull">NSNull</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Extensions.html#/c:objc(cs)NSString">NSString</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Extensions.html#/s:SS">String</a>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="nav-group-name">
|
||||
<a class="nav-group-name-link" href="../Protocols.html">Protocols</a>
|
||||
<ul class="nav-group-tasks">
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Protocols/ConfigSettable.html">ConfigSettable</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Protocols/SocketData.html">SocketData</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Protocols/SocketDataBufferable.html">SocketDataBufferable</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Protocols/SocketEngineClient.html">SocketEngineClient</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Protocols/SocketEnginePollable.html">SocketEnginePollable</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Protocols/SocketEngineSpec.html">SocketEngineSpec</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Protocols/SocketEngineWebsocket.html">SocketEngineWebsocket</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Protocols/SocketIOClientSpec.html">SocketIOClientSpec</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Protocols/SocketLogger.html">SocketLogger</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Protocols/SocketManagerSpec.html">SocketManagerSpec</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Protocols/SocketParsable.html">SocketParsable</a>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="nav-group-name">
|
||||
<a class="nav-group-name-link" href="../Structs.html">Structures</a>
|
||||
<ul class="nav-group-tasks">
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Structs/SocketEventHandler.html">SocketEventHandler</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Structs/SocketIOClientConfiguration.html">SocketIOClientConfiguration</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Structs/SocketPacket.html">SocketPacket</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Structs/SocketPacket/PacketType.html">– PacketType</a>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="nav-group-name">
|
||||
<a class="nav-group-name-link" href="../Typealiases.html">Type Aliases</a>
|
||||
<ul class="nav-group-tasks">
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Typealiases.html#/s:8SocketIO11AckCallbacka">AckCallback</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Typealiases.html#/s:8SocketIO14NormalCallbacka">NormalCallback</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Typealiases.html#/s:8SocketIO4Posta">Post</a>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
<article class="main-content">
|
||||
|
||||
<section class="section">
|
||||
<div class="section-content top-matter">
|
||||
<h1>SocketRawAckView</h1>
|
||||
<div class="declaration">
|
||||
<div class="language">
|
||||
|
||||
<pre class="highlight swift"><code><span class="kd">public</span> <span class="kd">final</span> <span class="kd">class</span> <span class="kt">SocketRawAckView</span> <span class="p">:</span> <span class="kt">NSObject</span></code></pre>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<p>Class that gives a backwards compatible way to cause an emit not to recursively check for Data objects.</p>
|
||||
|
||||
<p>Usage:</p>
|
||||
<pre class="highlight swift"><code><span class="n">ack</span><span class="o">.</span><span class="n">rawEmitView</span><span class="o">.</span><span class="nf">with</span><span class="p">(</span><span class="n">myObject</span><span class="p">)</span>
|
||||
</code></pre>
|
||||
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="section">
|
||||
<div class="section-content">
|
||||
<div class="task-group">
|
||||
<ul class="item-container">
|
||||
<li class="item">
|
||||
<div>
|
||||
<code>
|
||||
<a name="/s:8SocketIO0A10RawAckViewC4withyyAA0A4Data_pd_tF"></a>
|
||||
<a name="//apple_ref/swift/Method/with(_:)" class="dashAnchor"></a>
|
||||
<a class="token" href="#/s:8SocketIO0A10RawAckViewC4withyyAA0A4Data_pd_tF">with(_:<wbr>)</a>
|
||||
</code>
|
||||
</div>
|
||||
<div class="height-container">
|
||||
<div class="pointer-container"></div>
|
||||
<section class="section">
|
||||
<div class="pointer"></div>
|
||||
<div class="abstract">
|
||||
<p>Call to ack receiving this event.</p>
|
||||
|
||||
<p>If an error occurs trying to transform <code>items</code> into their socket representation, a <code><a href="../Enums/SocketClientEvent.html#/s:8SocketIO0A11ClientEventO5erroryA2CmF">SocketClientEvent.error</a></code>
|
||||
will be emitted. The structure of the error data is <code>[ackNum, items, theError]</code></p>
|
||||
|
||||
</div>
|
||||
<div class="declaration">
|
||||
<h4>Declaration</h4>
|
||||
<div class="language">
|
||||
<p class="aside-title">Swift</p>
|
||||
<pre class="highlight swift"><code><span class="kd">public</span> <span class="kd">func</span> <span class="nf">with</span><span class="p">(</span><span class="n">_</span> <span class="nv">items</span><span class="p">:</span> <span class="kt"><a href="../Protocols/SocketData.html">SocketData</a></span><span class="o">...</span><span class="p">)</span></code></pre>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<h4>Parameters</h4>
|
||||
<table class="graybox">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>
|
||||
<code>
|
||||
<em>items</em>
|
||||
</code>
|
||||
</td>
|
||||
<td>
|
||||
<div>
|
||||
<p>A variable number of items to send when acking.</p>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</li>
|
||||
<li class="item">
|
||||
<div>
|
||||
<code>
|
||||
<a name="/c:@M@SocketIO@objc(cs)SocketRawAckView(im)with:"></a>
|
||||
<a name="//apple_ref/swift/Method/with(_:)" class="dashAnchor"></a>
|
||||
<a class="token" href="#/c:@M@SocketIO@objc(cs)SocketRawAckView(im)with:">with(_:<wbr>)</a>
|
||||
</code>
|
||||
</div>
|
||||
<div class="height-container">
|
||||
<div class="pointer-container"></div>
|
||||
<section class="section">
|
||||
<div class="pointer"></div>
|
||||
<div class="abstract">
|
||||
<p>Call to ack receiving this event.</p>
|
||||
|
||||
</div>
|
||||
<div class="declaration">
|
||||
<h4>Declaration</h4>
|
||||
<div class="language">
|
||||
<p class="aside-title">Swift</p>
|
||||
<pre class="highlight swift"><code><span class="kd">@objc</span>
|
||||
<span class="kd">public</span> <span class="kd">func</span> <span class="nf">with</span><span class="p">(</span><span class="n">_</span> <span class="nv">items</span><span class="p">:</span> <span class="p">[</span><span class="kt">Any</span><span class="p">])</span></code></pre>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<h4>Parameters</h4>
|
||||
<table class="graybox">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>
|
||||
<code>
|
||||
<em>items</em>
|
||||
</code>
|
||||
</td>
|
||||
<td>
|
||||
<div>
|
||||
<p>An array of items to send when acking. Use <code>[]</code> to send nothing.</p>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
</article>
|
||||
</div>
|
||||
<section class="footer">
|
||||
<p>© 2021 <a class="link" href="https://github.com/socketio/socket.io-client-swift" target="_blank" rel="external">Erik</a>. All rights reserved. (Last updated: 2021-02-01)</p>
|
||||
<p>Generated by <a class="link" href="https://github.com/realm/jazzy" target="_blank" rel="external">jazzy ♪♫ v0.13.6</a>, a <a class="link" href="https://realm.io" target="_blank" rel="external">Realm</a> project.</p>
|
||||
</section>
|
||||
</body>
|
||||
</div>
|
||||
</html>
|
||||
532
docs/Classes/SocketRawView.html
Normal file
532
docs/Classes/SocketRawView.html
Normal file
@ -0,0 +1,532 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>SocketRawView Class Reference</title>
|
||||
<link rel="stylesheet" type="text/css" href="../css/jazzy.css" />
|
||||
<link rel="stylesheet" type="text/css" href="../css/highlight.css" />
|
||||
<meta charset="utf-8">
|
||||
<script src="../js/jquery.min.js" defer></script>
|
||||
<script src="../js/jazzy.js" defer></script>
|
||||
|
||||
<script src="../js/lunr.min.js" defer></script>
|
||||
<script src="../js/typeahead.jquery.js" defer></script>
|
||||
<script src="../js/jazzy.search.js" defer></script>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<a name="//apple_ref/swift/Class/SocketRawView" class="dashAnchor"></a>
|
||||
|
||||
<a title="SocketRawView Class Reference"></a>
|
||||
|
||||
<header class="header">
|
||||
<p class="header-col header-col--primary">
|
||||
<a class="header-link" href="../index.html">
|
||||
SocketIO 16.0.0 Docs
|
||||
</a>
|
||||
(100% documented)
|
||||
</p>
|
||||
|
||||
<p class="header-col--secondary">
|
||||
<form role="search" action="../search.json">
|
||||
<input type="text" placeholder="Search documentation" data-typeahead>
|
||||
</form>
|
||||
</p>
|
||||
|
||||
|
||||
</header>
|
||||
|
||||
<p class="breadcrumbs">
|
||||
<a class="breadcrumb" href="../index.html">SocketIO Reference</a>
|
||||
<img class="carat" src="../img/carat.png" />
|
||||
SocketRawView Class Reference
|
||||
</p>
|
||||
|
||||
<div class="content-wrapper">
|
||||
<nav class="navigation">
|
||||
<ul class="nav-groups">
|
||||
<li class="nav-group-name">
|
||||
<a class="nav-group-name-link" href="../Guides.html">Guides</a>
|
||||
<ul class="nav-group-tasks">
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../12to13.html">12to13</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../15to16.html">15to16</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../faq.html">FAQ</a>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="nav-group-name">
|
||||
<a class="nav-group-name-link" href="../Classes.html">Classes</a>
|
||||
<ul class="nav-group-tasks">
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Classes/OnAckCallback.html">OnAckCallback</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Classes/SocketAckEmitter.html">SocketAckEmitter</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Classes/SocketAnyEvent.html">SocketAnyEvent</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Classes/SocketEngine.html">SocketEngine</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Classes/SocketIOClient.html">SocketIOClient</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Classes/SocketManager.html">SocketManager</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Classes/SocketRawAckView.html">SocketRawAckView</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Classes/SocketRawView.html">SocketRawView</a>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="nav-group-name">
|
||||
<a class="nav-group-name-link" href="../Enums.html">Enumerations</a>
|
||||
<ul class="nav-group-tasks">
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Enums/SocketAckStatus.html">SocketAckStatus</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Enums/SocketClientEvent.html">SocketClientEvent</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Enums/SocketEnginePacketType.html">SocketEnginePacketType</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Enums/SocketIOClientOption.html">SocketIOClientOption</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Enums/SocketIOStatus.html">SocketIOStatus</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Enums/SocketIOVersion.html">SocketIOVersion</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Enums/SocketParsableError.html">SocketParsableError</a>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="nav-group-name">
|
||||
<a class="nav-group-name-link" href="../Extensions.html">Extensions</a>
|
||||
<ul class="nav-group-tasks">
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Extensions.html#/s:Sa">Array</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Extensions.html#/s:Sb">Bool</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Extensions.html#/s:10Foundation4DataV">Data</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Extensions.html#/s:SD">Dictionary</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Extensions.html#/s:Sd">Double</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Extensions.html#/s:Si">Int</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Extensions.html#/c:objc(cs)NSArray">NSArray</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Extensions.html#/c:objc(cs)NSData">NSData</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Extensions.html#/c:objc(cs)NSDictionary">NSDictionary</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Extensions.html#/c:objc(cs)NSNull">NSNull</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Extensions.html#/c:objc(cs)NSString">NSString</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Extensions.html#/s:SS">String</a>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="nav-group-name">
|
||||
<a class="nav-group-name-link" href="../Protocols.html">Protocols</a>
|
||||
<ul class="nav-group-tasks">
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Protocols/ConfigSettable.html">ConfigSettable</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Protocols/SocketData.html">SocketData</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Protocols/SocketDataBufferable.html">SocketDataBufferable</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Protocols/SocketEngineClient.html">SocketEngineClient</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Protocols/SocketEnginePollable.html">SocketEnginePollable</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Protocols/SocketEngineSpec.html">SocketEngineSpec</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Protocols/SocketEngineWebsocket.html">SocketEngineWebsocket</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Protocols/SocketIOClientSpec.html">SocketIOClientSpec</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Protocols/SocketLogger.html">SocketLogger</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Protocols/SocketManagerSpec.html">SocketManagerSpec</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Protocols/SocketParsable.html">SocketParsable</a>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="nav-group-name">
|
||||
<a class="nav-group-name-link" href="../Structs.html">Structures</a>
|
||||
<ul class="nav-group-tasks">
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Structs/SocketEventHandler.html">SocketEventHandler</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Structs/SocketIOClientConfiguration.html">SocketIOClientConfiguration</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Structs/SocketPacket.html">SocketPacket</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Structs/SocketPacket/PacketType.html">– PacketType</a>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="nav-group-name">
|
||||
<a class="nav-group-name-link" href="../Typealiases.html">Type Aliases</a>
|
||||
<ul class="nav-group-tasks">
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Typealiases.html#/s:8SocketIO11AckCallbacka">AckCallback</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Typealiases.html#/s:8SocketIO14NormalCallbacka">NormalCallback</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="../Typealiases.html#/s:8SocketIO4Posta">Post</a>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
<article class="main-content">
|
||||
|
||||
<section class="section">
|
||||
<div class="section-content top-matter">
|
||||
<h1>SocketRawView</h1>
|
||||
<div class="declaration">
|
||||
<div class="language">
|
||||
|
||||
<pre class="highlight swift"><code><span class="kd">public</span> <span class="kd">final</span> <span class="kd">class</span> <span class="kt">SocketRawView</span> <span class="p">:</span> <span class="kt">NSObject</span></code></pre>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<p>Class that gives a backwards compatible way to cause an emit not to recursively check for Data objects.</p>
|
||||
|
||||
<p>Usage:</p>
|
||||
<pre class="highlight swift"><code><span class="n">socket</span><span class="o">.</span><span class="n">rawEmitView</span><span class="o">.</span><span class="nf">emit</span><span class="p">(</span><span class="s">"myEvent"</span><span class="p">,</span> <span class="n">myObject</span><span class="p">)</span>
|
||||
</code></pre>
|
||||
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="section">
|
||||
<div class="section-content">
|
||||
<div class="task-group">
|
||||
<ul class="item-container">
|
||||
<li class="item">
|
||||
<div>
|
||||
<code>
|
||||
<a name="/s:8SocketIO0A7RawViewC4emityySS_AA0A4Data_pdtF"></a>
|
||||
<a name="//apple_ref/swift/Method/emit(_:_:)" class="dashAnchor"></a>
|
||||
<a class="token" href="#/s:8SocketIO0A7RawViewC4emityySS_AA0A4Data_pdtF">emit(_:<wbr>_:<wbr>)</a>
|
||||
</code>
|
||||
</div>
|
||||
<div class="height-container">
|
||||
<div class="pointer-container"></div>
|
||||
<section class="section">
|
||||
<div class="pointer"></div>
|
||||
<div class="abstract">
|
||||
<p>Send an event to the server, with optional data items.</p>
|
||||
|
||||
<p>If an error occurs trying to transform <code>items</code> into their socket representation, a <code><a href="../Enums/SocketClientEvent.html#/s:8SocketIO0A11ClientEventO5erroryA2CmF">SocketClientEvent.error</a></code>
|
||||
will be emitted. The structure of the error data is <code>[eventName, items, theError]</code></p>
|
||||
|
||||
</div>
|
||||
<div class="declaration">
|
||||
<h4>Declaration</h4>
|
||||
<div class="language">
|
||||
<p class="aside-title">Swift</p>
|
||||
<pre class="highlight swift"><code><span class="kd">public</span> <span class="kd">func</span> <span class="nf">emit</span><span class="p">(</span><span class="n">_</span> <span class="nv">event</span><span class="p">:</span> <span class="kt">String</span><span class="p">,</span> <span class="n">_</span> <span class="nv">items</span><span class="p">:</span> <span class="kt"><a href="../Protocols/SocketData.html">SocketData</a></span><span class="o">...</span><span class="p">)</span></code></pre>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<h4>Parameters</h4>
|
||||
<table class="graybox">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>
|
||||
<code>
|
||||
<em>event</em>
|
||||
</code>
|
||||
</td>
|
||||
<td>
|
||||
<div>
|
||||
<p>The event to send.</p>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<code>
|
||||
<em>items</em>
|
||||
</code>
|
||||
</td>
|
||||
<td>
|
||||
<div>
|
||||
<p>The items to send with this event. May be left out.</p>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</li>
|
||||
<li class="item">
|
||||
<div>
|
||||
<code>
|
||||
<a name="/c:@M@SocketIO@objc(cs)SocketRawView(im)emit:with:"></a>
|
||||
<a name="//apple_ref/swift/Method/emit(_:with:)" class="dashAnchor"></a>
|
||||
<a class="token" href="#/c:@M@SocketIO@objc(cs)SocketRawView(im)emit:with:">emit(_:<wbr>with:<wbr>)</a>
|
||||
</code>
|
||||
</div>
|
||||
<div class="height-container">
|
||||
<div class="pointer-container"></div>
|
||||
<section class="section">
|
||||
<div class="pointer"></div>
|
||||
<div class="abstract">
|
||||
<p>Same as emit, but meant for Objective-C</p>
|
||||
|
||||
</div>
|
||||
<div class="declaration">
|
||||
<h4>Declaration</h4>
|
||||
<div class="language">
|
||||
<p class="aside-title">Swift</p>
|
||||
<pre class="highlight swift"><code><span class="kd">@objc</span>
|
||||
<span class="kd">public</span> <span class="kd">func</span> <span class="nf">emit</span><span class="p">(</span><span class="n">_</span> <span class="nv">event</span><span class="p">:</span> <span class="kt">String</span><span class="p">,</span> <span class="n">with</span> <span class="nv">items</span><span class="p">:</span> <span class="p">[</span><span class="kt">Any</span><span class="p">])</span></code></pre>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<h4>Parameters</h4>
|
||||
<table class="graybox">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>
|
||||
<code>
|
||||
<em>event</em>
|
||||
</code>
|
||||
</td>
|
||||
<td>
|
||||
<div>
|
||||
<p>The event to send.</p>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<code>
|
||||
<em>items</em>
|
||||
</code>
|
||||
</td>
|
||||
<td>
|
||||
<div>
|
||||
<p>The items to send with this event. Send an empty array to send no data.</p>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</li>
|
||||
<li class="item">
|
||||
<div>
|
||||
<code>
|
||||
<a name="/s:8SocketIO0A7RawViewC11emitWithAckyAA02OnG8CallbackCSS_AA0A4Data_pdtF"></a>
|
||||
<a name="//apple_ref/swift/Method/emitWithAck(_:_:)" class="dashAnchor"></a>
|
||||
<a class="token" href="#/s:8SocketIO0A7RawViewC11emitWithAckyAA02OnG8CallbackCSS_AA0A4Data_pdtF">emitWithAck(_:<wbr>_:<wbr>)</a>
|
||||
</code>
|
||||
</div>
|
||||
<div class="height-container">
|
||||
<div class="pointer-container"></div>
|
||||
<section class="section">
|
||||
<div class="pointer"></div>
|
||||
<div class="abstract">
|
||||
<p>Sends a message to the server, requesting an ack.</p>
|
||||
|
||||
<p><strong>NOTE</strong>: It is up to the server send an ack back, just calling this method does not mean the server will ack.
|
||||
Check that your server’s api will ack the event being sent.</p>
|
||||
|
||||
<p>If an error occurs trying to transform <code>items</code> into their socket representation, a <code><a href="../Enums/SocketClientEvent.html#/s:8SocketIO0A11ClientEventO5erroryA2CmF">SocketClientEvent.error</a></code>
|
||||
will be emitted. The structure of the error data is <code>[eventName, items, theError]</code></p>
|
||||
|
||||
<p>Example:</p>
|
||||
<pre class="highlight swift"><code><span class="n">socket</span><span class="o">.</span><span class="nf">emitWithAck</span><span class="p">(</span><span class="s">"myEvent"</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span><span class="o">.</span><span class="nf">timingOut</span><span class="p">(</span><span class="nv">after</span><span class="p">:</span> <span class="mi">1</span><span class="p">)</span> <span class="p">{</span><span class="n">data</span> <span class="k">in</span>
|
||||
<span class="o">...</span>
|
||||
<span class="p">}</span>
|
||||
</code></pre>
|
||||
|
||||
</div>
|
||||
<div class="declaration">
|
||||
<h4>Declaration</h4>
|
||||
<div class="language">
|
||||
<p class="aside-title">Swift</p>
|
||||
<pre class="highlight swift"><code><span class="kd">public</span> <span class="kd">func</span> <span class="nf">emitWithAck</span><span class="p">(</span><span class="n">_</span> <span class="nv">event</span><span class="p">:</span> <span class="kt">String</span><span class="p">,</span> <span class="n">_</span> <span class="nv">items</span><span class="p">:</span> <span class="kt"><a href="../Protocols/SocketData.html">SocketData</a></span><span class="o">...</span><span class="p">)</span> <span class="o">-></span> <span class="kt"><a href="../Classes/OnAckCallback.html">OnAckCallback</a></span></code></pre>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<h4>Parameters</h4>
|
||||
<table class="graybox">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>
|
||||
<code>
|
||||
<em>event</em>
|
||||
</code>
|
||||
</td>
|
||||
<td>
|
||||
<div>
|
||||
<p>The event to send.</p>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<code>
|
||||
<em>items</em>
|
||||
</code>
|
||||
</td>
|
||||
<td>
|
||||
<div>
|
||||
<p>The items to send with this event. May be left out.</p>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div>
|
||||
<h4>Return Value</h4>
|
||||
<p>An <code><a href="../Classes/OnAckCallback.html">OnAckCallback</a></code>. You must call the <code>timingOut(after:)</code> method before the event will be sent.</p>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</li>
|
||||
<li class="item">
|
||||
<div>
|
||||
<code>
|
||||
<a name="/c:@M@SocketIO@objc(cs)SocketRawView(im)emitWithAck:with:"></a>
|
||||
<a name="//apple_ref/swift/Method/emitWithAck(_:with:)" class="dashAnchor"></a>
|
||||
<a class="token" href="#/c:@M@SocketIO@objc(cs)SocketRawView(im)emitWithAck:with:">emitWithAck(_:<wbr>with:<wbr>)</a>
|
||||
</code>
|
||||
</div>
|
||||
<div class="height-container">
|
||||
<div class="pointer-container"></div>
|
||||
<section class="section">
|
||||
<div class="pointer"></div>
|
||||
<div class="abstract">
|
||||
<p>Same as emitWithAck, but for Objective-C</p>
|
||||
|
||||
<p><strong>NOTE</strong>: It is up to the server send an ack back, just calling this method does not mean the server will ack.
|
||||
Check that your server’s api will ack the event being sent.</p>
|
||||
|
||||
<p>Example:</p>
|
||||
<pre class="highlight swift"><code><span class="n">socket</span><span class="o">.</span><span class="nf">emitWithAck</span><span class="p">(</span><span class="s">"myEvent"</span><span class="p">,</span> <span class="nv">with</span><span class="p">:</span> <span class="p">[</span><span class="mi">1</span><span class="p">])</span><span class="o">.</span><span class="nf">timingOut</span><span class="p">(</span><span class="nv">after</span><span class="p">:</span> <span class="mi">1</span><span class="p">)</span> <span class="p">{</span><span class="n">data</span> <span class="k">in</span>
|
||||
<span class="o">...</span>
|
||||
<span class="p">}</span>
|
||||
</code></pre>
|
||||
|
||||
</div>
|
||||
<div class="declaration">
|
||||
<h4>Declaration</h4>
|
||||
<div class="language">
|
||||
<p class="aside-title">Swift</p>
|
||||
<pre class="highlight swift"><code><span class="kd">@objc</span>
|
||||
<span class="kd">public</span> <span class="kd">func</span> <span class="nf">emitWithAck</span><span class="p">(</span><span class="n">_</span> <span class="nv">event</span><span class="p">:</span> <span class="kt">String</span><span class="p">,</span> <span class="n">with</span> <span class="nv">items</span><span class="p">:</span> <span class="p">[</span><span class="kt">Any</span><span class="p">])</span> <span class="o">-></span> <span class="kt"><a href="../Classes/OnAckCallback.html">OnAckCallback</a></span></code></pre>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<h4>Parameters</h4>
|
||||
<table class="graybox">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>
|
||||
<code>
|
||||
<em>event</em>
|
||||
</code>
|
||||
</td>
|
||||
<td>
|
||||
<div>
|
||||
<p>The event to send.</p>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<code>
|
||||
<em>items</em>
|
||||
</code>
|
||||
</td>
|
||||
<td>
|
||||
<div>
|
||||
<p>The items to send with this event. Use <code>[]</code> to send nothing.</p>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div>
|
||||
<h4>Return Value</h4>
|
||||
<p>An <code><a href="../Classes/OnAckCallback.html">OnAckCallback</a></code>. You must call the <code>timingOut(after:)</code> method before the event will be sent.</p>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
</article>
|
||||
</div>
|
||||
<section class="footer">
|
||||
<p>© 2021 <a class="link" href="https://github.com/socketio/socket.io-client-swift" target="_blank" rel="external">Erik</a>. All rights reserved. (Last updated: 2021-02-01)</p>
|
||||
<p>Generated by <a class="link" href="https://github.com/realm/jazzy" target="_blank" rel="external">jazzy ♪♫ v0.13.6</a>, a <a class="link" href="https://realm.io" target="_blank" rel="external">Realm</a> project.</p>
|
||||
</section>
|
||||
</body>
|
||||
</div>
|
||||
</html>
|
||||
453
docs/Enums.html
Normal file
453
docs/Enums.html
Normal file
@ -0,0 +1,453 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>Enumerations Reference</title>
|
||||
<link rel="stylesheet" type="text/css" href="css/jazzy.css" />
|
||||
<link rel="stylesheet" type="text/css" href="css/highlight.css" />
|
||||
<meta charset="utf-8">
|
||||
<script src="js/jquery.min.js" defer></script>
|
||||
<script src="js/jazzy.js" defer></script>
|
||||
|
||||
<script src="js/lunr.min.js" defer></script>
|
||||
<script src="js/typeahead.jquery.js" defer></script>
|
||||
<script src="js/jazzy.search.js" defer></script>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<a name="//apple_ref/swift/Section/Enumerations" class="dashAnchor"></a>
|
||||
|
||||
<a title="Enumerations Reference"></a>
|
||||
|
||||
<header class="header">
|
||||
<p class="header-col header-col--primary">
|
||||
<a class="header-link" href="index.html">
|
||||
SocketIO 16.0.0 Docs
|
||||
</a>
|
||||
(100% documented)
|
||||
</p>
|
||||
|
||||
<p class="header-col--secondary">
|
||||
<form role="search" action="search.json">
|
||||
<input type="text" placeholder="Search documentation" data-typeahead>
|
||||
</form>
|
||||
</p>
|
||||
|
||||
|
||||
</header>
|
||||
|
||||
<p class="breadcrumbs">
|
||||
<a class="breadcrumb" href="index.html">SocketIO Reference</a>
|
||||
<img class="carat" src="img/carat.png" />
|
||||
Enumerations Reference
|
||||
</p>
|
||||
|
||||
<div class="content-wrapper">
|
||||
<nav class="navigation">
|
||||
<ul class="nav-groups">
|
||||
<li class="nav-group-name">
|
||||
<a class="nav-group-name-link" href="Guides.html">Guides</a>
|
||||
<ul class="nav-group-tasks">
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="12to13.html">12to13</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="15to16.html">15to16</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="faq.html">FAQ</a>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="nav-group-name">
|
||||
<a class="nav-group-name-link" href="Classes.html">Classes</a>
|
||||
<ul class="nav-group-tasks">
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="Classes/OnAckCallback.html">OnAckCallback</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="Classes/SocketAckEmitter.html">SocketAckEmitter</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="Classes/SocketAnyEvent.html">SocketAnyEvent</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="Classes/SocketEngine.html">SocketEngine</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="Classes/SocketIOClient.html">SocketIOClient</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="Classes/SocketManager.html">SocketManager</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="Classes/SocketRawAckView.html">SocketRawAckView</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="Classes/SocketRawView.html">SocketRawView</a>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="nav-group-name">
|
||||
<a class="nav-group-name-link" href="Enums.html">Enumerations</a>
|
||||
<ul class="nav-group-tasks">
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="Enums/SocketAckStatus.html">SocketAckStatus</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="Enums/SocketClientEvent.html">SocketClientEvent</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="Enums/SocketEnginePacketType.html">SocketEnginePacketType</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="Enums/SocketIOClientOption.html">SocketIOClientOption</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="Enums/SocketIOStatus.html">SocketIOStatus</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="Enums/SocketIOVersion.html">SocketIOVersion</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="Enums/SocketParsableError.html">SocketParsableError</a>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="nav-group-name">
|
||||
<a class="nav-group-name-link" href="Extensions.html">Extensions</a>
|
||||
<ul class="nav-group-tasks">
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="Extensions.html#/s:Sa">Array</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="Extensions.html#/s:Sb">Bool</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="Extensions.html#/s:10Foundation4DataV">Data</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="Extensions.html#/s:SD">Dictionary</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="Extensions.html#/s:Sd">Double</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="Extensions.html#/s:Si">Int</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="Extensions.html#/c:objc(cs)NSArray">NSArray</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="Extensions.html#/c:objc(cs)NSData">NSData</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="Extensions.html#/c:objc(cs)NSDictionary">NSDictionary</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="Extensions.html#/c:objc(cs)NSNull">NSNull</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="Extensions.html#/c:objc(cs)NSString">NSString</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="Extensions.html#/s:SS">String</a>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="nav-group-name">
|
||||
<a class="nav-group-name-link" href="Protocols.html">Protocols</a>
|
||||
<ul class="nav-group-tasks">
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="Protocols/ConfigSettable.html">ConfigSettable</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="Protocols/SocketData.html">SocketData</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="Protocols/SocketDataBufferable.html">SocketDataBufferable</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="Protocols/SocketEngineClient.html">SocketEngineClient</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="Protocols/SocketEnginePollable.html">SocketEnginePollable</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="Protocols/SocketEngineSpec.html">SocketEngineSpec</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="Protocols/SocketEngineWebsocket.html">SocketEngineWebsocket</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="Protocols/SocketIOClientSpec.html">SocketIOClientSpec</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="Protocols/SocketLogger.html">SocketLogger</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="Protocols/SocketManagerSpec.html">SocketManagerSpec</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="Protocols/SocketParsable.html">SocketParsable</a>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="nav-group-name">
|
||||
<a class="nav-group-name-link" href="Structs.html">Structures</a>
|
||||
<ul class="nav-group-tasks">
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="Structs/SocketEventHandler.html">SocketEventHandler</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="Structs/SocketIOClientConfiguration.html">SocketIOClientConfiguration</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="Structs/SocketPacket.html">SocketPacket</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="Structs/SocketPacket/PacketType.html">– PacketType</a>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="nav-group-name">
|
||||
<a class="nav-group-name-link" href="Typealiases.html">Type Aliases</a>
|
||||
<ul class="nav-group-tasks">
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="Typealiases.html#/s:8SocketIO11AckCallbacka">AckCallback</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="Typealiases.html#/s:8SocketIO14NormalCallbacka">NormalCallback</a>
|
||||
</li>
|
||||
<li class="nav-group-task">
|
||||
<a class="nav-group-task-link" href="Typealiases.html#/s:8SocketIO4Posta">Post</a>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
<article class="main-content">
|
||||
|
||||
<section class="section">
|
||||
<div class="section-content top-matter">
|
||||
<h1>Enumerations</h1>
|
||||
<p>The following enumerations are available globally.</p>
|
||||
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="section">
|
||||
<div class="section-content">
|
||||
<div class="task-group">
|
||||
<ul class="item-container">
|
||||
<li class="item">
|
||||
<div>
|
||||
<code>
|
||||
<a name="/s:8SocketIO0A9AckStatusO"></a>
|
||||
<a name="//apple_ref/swift/Enum/SocketAckStatus" class="dashAnchor"></a>
|
||||
<a class="token" href="#/s:8SocketIO0A9AckStatusO">SocketAckStatus</a>
|
||||
</code>
|
||||
</div>
|
||||
<div class="height-container">
|
||||
<div class="pointer-container"></div>
|
||||
<section class="section">
|
||||
<div class="pointer"></div>
|
||||
<div class="abstract">
|
||||
<p>The status of an ack.</p>
|
||||
|
||||
<a href="Enums/SocketAckStatus.html" class="slightly-smaller">See more</a>
|
||||
</div>
|
||||
<div class="declaration">
|
||||
<h4>Declaration</h4>
|
||||
<div class="language">
|
||||
<p class="aside-title">Swift</p>
|
||||
<pre class="highlight swift"><code><span class="kd">public</span> <span class="kd">enum</span> <span class="kt">SocketAckStatus</span> <span class="p">:</span> <span class="kt">String</span></code></pre>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</li>
|
||||
<li class="item">
|
||||
<div>
|
||||
<code>
|
||||
<a name="/s:8SocketIO0A9IOVersionO"></a>
|
||||
<a name="//apple_ref/swift/Enum/SocketIOVersion" class="dashAnchor"></a>
|
||||
<a class="token" href="#/s:8SocketIO0A9IOVersionO">SocketIOVersion</a>
|
||||
</code>
|
||||
</div>
|
||||
<div class="height-container">
|
||||
<div class="pointer-container"></div>
|
||||
<section class="section">
|
||||
<div class="pointer"></div>
|
||||
<div class="abstract">
|
||||
<p>The socket.io version being used.</p>
|
||||
|
||||
<a href="Enums/SocketIOVersion.html" class="slightly-smaller">See more</a>
|
||||
</div>
|
||||
<div class="declaration">
|
||||
<h4>Declaration</h4>
|
||||
<div class="language">
|
||||
<p class="aside-title">Swift</p>
|
||||
<pre class="highlight swift"><code><span class="kd">public</span> <span class="kd">enum</span> <span class="kt">SocketIOVersion</span> <span class="p">:</span> <span class="kt">Int</span></code></pre>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</li>
|
||||
<li class="item">
|
||||
<div>
|
||||
<code>
|
||||
<a name="/s:8SocketIO0A14IOClientOptionO"></a>
|
||||
<a name="//apple_ref/swift/Enum/SocketIOClientOption" class="dashAnchor"></a>
|
||||
<a class="token" href="#/s:8SocketIO0A14IOClientOptionO">SocketIOClientOption</a>
|
||||
</code>
|
||||
</div>
|
||||
<div class="height-container">
|
||||
<div class="pointer-container"></div>
|
||||
<section class="section">
|
||||
<div class="pointer"></div>
|
||||
<div class="abstract">
|
||||
<p>The options for a client.</p>
|
||||
|
||||
<a href="Enums/SocketIOClientOption.html" class="slightly-smaller">See more</a>
|
||||
</div>
|
||||
<div class="declaration">
|
||||
<h4>Declaration</h4>
|
||||
<div class="language">
|
||||
<p class="aside-title">Swift</p>
|
||||
<pre class="highlight swift"><code><span class="kd">public</span> <span class="kd">enum</span> <span class="kt">SocketIOClientOption</span> <span class="p">:</span> <span class="kt">ClientOption</span></code></pre>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</li>
|
||||
<li class="item">
|
||||
<div>
|
||||
<code>
|
||||
<a name="/s:8SocketIO0A11ClientEventO"></a>
|
||||
<a name="//apple_ref/swift/Enum/SocketClientEvent" class="dashAnchor"></a>
|
||||
<a class="token" href="#/s:8SocketIO0A11ClientEventO">SocketClientEvent</a>
|
||||
</code>
|
||||
</div>
|
||||
<div class="height-container">
|
||||
<div class="pointer-container"></div>
|
||||
<section class="section">
|
||||
<div class="pointer"></div>
|
||||
<div class="abstract">
|
||||
<p>The set of events that are generated by the client.</p>
|
||||
|
||||
<a href="Enums/SocketClientEvent.html" class="slightly-smaller">See more</a>
|
||||
</div>
|
||||
<div class="declaration">
|
||||
<h4>Declaration</h4>
|
||||
<div class="language">
|
||||
<p class="aside-title">Swift</p>
|
||||
<pre class="highlight swift"><code><span class="kd">public</span> <span class="kd">enum</span> <span class="kt">SocketClientEvent</span> <span class="p">:</span> <span class="kt">String</span></code></pre>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</li>
|
||||
<li class="item">
|
||||
<div>
|
||||
<code>
|
||||
<a name="/c:@M@SocketIO@E@SocketIOStatus"></a>
|
||||
<a name="//apple_ref/swift/Enum/SocketIOStatus" class="dashAnchor"></a>
|
||||
<a class="token" href="#/c:@M@SocketIO@E@SocketIOStatus">SocketIOStatus</a>
|
||||
</code>
|
||||
</div>
|
||||
<div class="height-container">
|
||||
<div class="pointer-container"></div>
|
||||
<section class="section">
|
||||
<div class="pointer"></div>
|
||||
<div class="abstract">
|
||||
<p>Represents state of a manager or client.</p>
|
||||
|
||||
<a href="Enums/SocketIOStatus.html" class="slightly-smaller">See more</a>
|
||||
</div>
|
||||
<div class="declaration">
|
||||
<h4>Declaration</h4>
|
||||
<div class="language">
|
||||
<p class="aside-title">Swift</p>
|
||||
<pre class="highlight swift"><code><span class="kd">@objc</span>
|
||||
<span class="kd">public</span> <span class="kd">enum</span> <span class="kt">SocketIOStatus</span> <span class="p">:</span> <span class="kt">Int</span><span class="p">,</span> <span class="kt">CustomStringConvertible</span></code></pre>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</li>
|
||||
<li class="item">
|
||||
<div>
|
||||
<code>
|
||||
<a name="/c:@M@SocketIO@E@SocketEnginePacketType"></a>
|
||||
<a name="//apple_ref/swift/Enum/SocketEnginePacketType" class="dashAnchor"></a>
|
||||
<a class="token" href="#/c:@M@SocketIO@E@SocketEnginePacketType">SocketEnginePacketType</a>
|
||||
</code>
|
||||
</div>
|
||||
<div class="height-container">
|
||||
<div class="pointer-container"></div>
|
||||
<section class="section">
|
||||
<div class="pointer"></div>
|
||||
<div class="abstract">
|
||||
<p>Represents the type of engine.io packet types.</p>
|
||||
|
||||
<a href="Enums/SocketEnginePacketType.html" class="slightly-smaller">See more</a>
|
||||
</div>
|
||||
<div class="declaration">
|
||||
<h4>Declaration</h4>
|
||||
<div class="language">
|
||||
<p class="aside-title">Swift</p>
|
||||
<pre class="highlight swift"><code><span class="kd">@objc</span>
|
||||
<span class="kd">public</span> <span class="kd">enum</span> <span class="kt">SocketEnginePacketType</span> <span class="p">:</span> <span class="kt">Int</span></code></pre>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</li>
|
||||
<li class="item">
|
||||
<div>
|
||||
<code>
|
||||
<a name="/s:8SocketIO0A13ParsableErrorO"></a>
|
||||
<a name="//apple_ref/swift/Enum/SocketParsableError" class="dashAnchor"></a>
|
||||
<a class="token" href="#/s:8SocketIO0A13ParsableErrorO">SocketParsableError</a>
|
||||
</code>
|
||||
</div>
|
||||
<div class="height-container">
|
||||
<div class="pointer-container"></div>
|
||||
<section class="section">
|
||||
<div class="pointer"></div>
|
||||
<div class="abstract">
|
||||
<p>Errors that can be thrown during parsing.</p>
|
||||
|
||||
<a href="Enums/SocketParsableError.html" class="slightly-smaller">See more</a>
|
||||
</div>
|
||||
<div class="declaration">
|
||||
<h4>Declaration</h4>
|
||||
<div class="language">
|
||||
<p class="aside-title">Swift</p>
|
||||
<pre class="highlight swift"><code><span class="kd">public</span> <span class="kd">enum</span> <span class="kt">SocketParsableError</span> <span class="p">:</span> <span class="kt">Error</span></code></pre>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
</article>
|
||||
</div>
|
||||
<section class="footer">
|
||||
<p>© 2021 <a class="link" href="https://github.com/socketio/socket.io-client-swift" target="_blank" rel="external">Erik</a>. All rights reserved. (Last updated: 2021-02-01)</p>
|
||||
<p>Generated by <a class="link" href="https://github.com/realm/jazzy" target="_blank" rel="external">jazzy ♪♫ v0.13.6</a>, a <a class="link" href="https://realm.io" target="_blank" rel="external">Realm</a> project.</p>
|
||||
</section>
|
||||
</body>
|
||||
</div>
|
||||
</html>
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user