Procházet zdrojové kódy

Add some very first parts of the network code.

Mathias Gottschlag před 5 roky
rodič
revize
ec0b9ecc4d
8 změnil soubory, kde provedl 322 přidání a 0 odebrání
  1. 37
    0
      Cargo.lock
  2. 1
    0
      Cargo.toml
  3. 4
    0
      src/lib.rs
  4. 21
    0
      src/network/client.rs
  5. 3
    0
      src/network/mod.rs
  6. 117
    0
      src/network/packet_connection.rs
  7. 1
    0
      src/network/server.rs
  8. 138
    0
      src/protocol.rs

+ 37
- 0
Cargo.lock Zobrazit soubor

@@ -53,6 +53,11 @@ name = "autocfg"
53 53
 version = "0.1.7"
54 54
 source = "registry+https://github.com/rust-lang/crates.io-index"
55 55
 
56
+[[package]]
57
+name = "autocfg"
58
+version = "1.0.0"
59
+source = "registry+https://github.com/rust-lang/crates.io-index"
60
+
56 61
 [[package]]
57 62
 name = "base64"
58 63
 version = "0.11.0"
@@ -520,6 +525,14 @@ dependencies = [
520 525
  "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
521 526
 ]
522 527
 
528
+[[package]]
529
+name = "num-traits"
530
+version = "0.2.11"
531
+source = "registry+https://github.com/rust-lang/crates.io-index"
532
+dependencies = [
533
+ "autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
534
+]
535
+
523 536
 [[package]]
524 537
 name = "num_cpus"
525 538
 version = "1.12.0"
@@ -700,6 +713,25 @@ name = "regex-syntax"
700 713
 version = "0.6.14"
701 714
 source = "registry+https://github.com/rust-lang/crates.io-index"
702 715
 
716
+[[package]]
717
+name = "rmp"
718
+version = "0.8.9"
719
+source = "registry+https://github.com/rust-lang/crates.io-index"
720
+dependencies = [
721
+ "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
722
+ "num-traits 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
723
+]
724
+
725
+[[package]]
726
+name = "rmp-serde"
727
+version = "0.14.3"
728
+source = "registry+https://github.com/rust-lang/crates.io-index"
729
+dependencies = [
730
+ "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
731
+ "rmp 0.8.9 (registry+https://github.com/rust-lang/crates.io-index)",
732
+ "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)",
733
+]
734
+
703 735
 [[package]]
704 736
 name = "rust-argon2"
705 737
 version = "0.7.0"
@@ -906,6 +938,7 @@ dependencies = [
906 938
  "futures 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
907 939
  "futures-tokio-compat 0.1.0 (git+https://github.com/mgottschlag/futures-tokio-compat.git)",
908 940
  "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
941
+ "rmp-serde 0.14.3 (registry+https://github.com/rust-lang/crates.io-index)",
909 942
  "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)",
910 943
  "serde_json 1.0.45 (registry+https://github.com/rust-lang/crates.io-index)",
911 944
  "structopt 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1027,6 +1060,7 @@ dependencies = [
1027 1060
 "checksum async-tungstenite 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "37250bc739b253cf2d861047a7bcaad1d46d1d027070b44dbeab9168b40cf407"
1028 1061
 "checksum atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
1029 1062
 "checksum autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "1d49d90015b3c36167a20fe2810c5cd875ad504b39cff3d4eae7977e6b7c1cb2"
1063
+"checksum autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d"
1030 1064
 "checksum base64 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b41b7ea54a0c9d92199de89e20e58d49f02f8e699814ef3fdf266f6f748d15c7"
1031 1065
 "checksum bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
1032 1066
 "checksum blake2b_simd 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)" = "d8fb2d74254a3a0b5cac33ac9f8ed0e44aa50378d9dbb2e5d83bd21ed1dc2c8a"
@@ -1083,6 +1117,7 @@ dependencies = [
1083 1117
 "checksum mio-uds 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)" = "966257a94e196b11bb43aca423754d87429960a768de9414f3691d6957abf125"
1084 1118
 "checksum miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f2f3b1cf331de6896aabf6e9d55dca90356cc9960cca7eaaf408a355ae919"
1085 1119
 "checksum net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)" = "42550d9fb7b6684a6d404d9fa7250c2eb2646df731d1c06afc06dcee9e1bcf88"
1120
+"checksum num-traits 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "c62be47e61d1842b9170f0fdeec8eba98e60e90e5446449a0545e5152acd7096"
1086 1121
 "checksum num_cpus 1.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "46203554f085ff89c235cd12f7075f3233af9b11ed7c9e16dfe2560d03313ce6"
1087 1122
 "checksum opaque-debug 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c"
1088 1123
 "checksum percent-encoding 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e"
@@ -1106,6 +1141,8 @@ dependencies = [
1106 1141
 "checksum redox_users 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "09b23093265f8d200fa7b4c2c76297f47e681c655f6f1285a8780d6a022f7431"
1107 1142
 "checksum regex 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "322cf97724bea3ee221b78fe25ac9c46114ebb51747ad5babd51a2fc6a8235a8"
1108 1143
 "checksum regex-syntax 0.6.14 (registry+https://github.com/rust-lang/crates.io-index)" = "b28dfe3fe9badec5dbf0a79a9cccad2cfc2ab5484bdb3e44cbd1ae8b3ba2be06"
1144
+"checksum rmp 0.8.9 (registry+https://github.com/rust-lang/crates.io-index)" = "0f10b46df14cf1ee1ac7baa4d2fbc2c52c0622a4b82fa8740e37bc452ac0184f"
1145
+"checksum rmp-serde 0.14.3 (registry+https://github.com/rust-lang/crates.io-index)" = "4c1ee98f14fe8b8e9c5ea13d25da7b2a1796169202c57a09d7288de90d56222b"
1109 1146
 "checksum rust-argon2 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2bc8af4bda8e1ff4932523b94d3dd20ee30a87232323eda55903ffd71d2fb017"
1110 1147
 "checksum rustversion 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b3bba175698996010c4f6dce5e7f173b6eb781fce25d2cfc45e27091ce0b79f6"
1111 1148
 "checksum ryu 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "bfa8506c1de11c9c4e4c38863ccbe02a305c8188e85a05a784c9e11e1c3910c8"

+ 1
- 0
Cargo.toml Zobrazit soubor

@@ -16,4 +16,5 @@ futures-tokio-compat = { git = "https://github.com/mgottschlag/futures-tokio-com
16 16
 async-tungstenite = { version = "0.3", features = ["tokio-runtime"] }
17 17
 env_logger = "0.7"
18 18
 log = "0.4"
19
+rmp-serde = "0.14"
19 20
 fswatcher = { git = "https://github.com/mgottschlag/fswatcher-rs.git" }

+ 4
- 0
src/lib.rs Zobrazit soubor

@@ -1,8 +1,12 @@
1
+extern crate rmp_serde as rmps;
2
+
1 3
 use std::io;
2 4
 
3 5
 mod database;
4 6
 mod file_system_watcher;
5 7
 mod file_tree;
8
+pub mod network;
9
+pub mod protocol;
6 10
 
7 11
 pub use database::Database;
8 12
 pub use file_system_watcher::FileSystemWatcher;

+ 21
- 0
src/network/client.rs Zobrazit soubor

@@ -0,0 +1,21 @@
1
+use futures::Future;
2
+use serde::de::DeserializeOwned;
3
+use serde::Serialize;
4
+
5
+use std::time::Duration;
6
+
7
+trait Connection {
8
+    type Request: Serialize;
9
+    type Response: DeserializeOwned; // TODO: Better lifetime for zero-copy deserialization of large amounts of data?
10
+    type Call: RemoteCall<Output = Self::Response>;
11
+
12
+    fn call(call: Self::Request) -> Self::Call;
13
+
14
+    // TODO: Server-client events.
15
+}
16
+
17
+trait RemoteCall: Future {
18
+    // TODO
19
+
20
+    fn with_timeout(self, timeout: Duration) -> Self;
21
+}

+ 3
- 0
src/network/mod.rs Zobrazit soubor

@@ -0,0 +1,3 @@
1
+mod client;
2
+mod packet_connection;
3
+mod server;

+ 117
- 0
src/network/packet_connection.rs Zobrazit soubor

@@ -0,0 +1,117 @@
1
+//! Module which implements a low-level packet protocol over websockets.
2
+//!
3
+//! The low-level protocol needs to implement two basic pieces of functionality: It needs to be
4
+//! able to implement remote procedure calls from the client to the server, and it needs to
5
+//! provide a method for the server to send asynchronous events. A protocol for both cases is
6
+//! outlined below, where each packet is sent as one WebSocket message.
7
+//!
8
+//! Remote procedure call:
9
+//! - The client allocates an ID from the range between 0..2^31-1 that is not currently in use
10
+//!   for another RPC in progress.
11
+//! - The client prepares a packet with this ID, "response = false", and the appropriate
12
+//!   payload and sends the packet to the server.
13
+//! - The server receives the packet, processes the request and sends a packet back with the
14
+//!   identical ID and "response = true".
15
+//! - In case of an error, the payload has the type "Error" which in turn contains the error
16
+//!   type.
17
+//! - Unpon reception of the response, the client is free to reuse the ID for further RPCs.
18
+//! Note that this protocol does not allow the client to cancel an RPC that is currently in
19
+//! progress - implementing such functionality is difficult, error-prone, and most likely not
20
+//! worth the effort.
21
+//!
22
+//! Server-side event:
23
+//! - The server creates a packet with the ID 2^31 and the event content and sends it to the
24
+//!   client.
25
+//! Note that the client does not have any method to acknowledge event reception. As events are
26
+//! asynchronous compared to RPCs on the same connection, the event type needs to be designed in
27
+//! a way that no such temporal information is necessary to process the events.
28
+//! TODO: Example to demonstrate the problem.
29
+
30
+use serde::de::DeserializeOwned;
31
+use serde::{Deserialize, Serialize};
32
+
33
+trait PacketConnection {
34
+    type Payload: Serialize + DeserializeOwned;
35
+
36
+    // TODO
37
+}
38
+
39
+#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
40
+pub struct Packet<Payload> {
41
+    pub id: u32,
42
+    pub response: bool,
43
+    pub payload: Payload,
44
+}
45
+
46
+#[cfg(test)]
47
+mod tests {
48
+    use rmps::Serializer;
49
+
50
+    use super::*;
51
+    use crate::protocol::{PacketPayload, ServerInfoResponse};
52
+
53
+    /// Test whether serialization of packets matches the expected values.
54
+    /// TODO: TGhese tests should be in protocol.rs.
55
+    #[test]
56
+    fn test_serde_compatibility() {
57
+        let tests = [
58
+            (
59
+                Packet {
60
+                    id: 42,
61
+                    response: false,
62
+                    payload: PacketPayload::ServerInfo,
63
+                },
64
+                vec![
65
+                    131, 162, 105, 100, 42, 168, 114, 101, 115, 112, 111, 110, 115, 101, 194, 167,
66
+                    112, 97, 121, 108, 111, 97, 100, 129, 170, 83, 101, 114, 118, 101, 114, 73,
67
+                    110, 102, 111, 192,
68
+                ],
69
+            ),
70
+            (
71
+                Packet {
72
+                    id: 42,
73
+                    response: true,
74
+                    payload: PacketPayload::ServerInfoResponse(ServerInfoResponse {
75
+                        version: "0.1".to_owned(),
76
+                    }),
77
+                },
78
+                vec![
79
+                    131, 162, 105, 100, 42, 168, 114, 101, 115, 112, 111, 110, 115, 101, 195, 167,
80
+                    112, 97, 121, 108, 111, 97, 100, 129, 178, 83, 101, 114, 118, 101, 114, 73,
81
+                    110, 102, 111, 82, 101, 115, 112, 111, 110, 115, 101, 129, 167, 118, 101, 114,
82
+                    115, 105, 111, 110, 163, 48, 46, 49,
83
+                ],
84
+            ),
85
+            (
86
+                Packet {
87
+                    id: 42,
88
+                    response: true,
89
+                    payload: PacketPayload::Error(crate::protocol::Error::InvalidParameter),
90
+                },
91
+                vec![
92
+                    131, 162, 105, 100, 42, 168, 114, 101, 115, 112, 111, 110, 115, 101, 195, 167,
93
+                    112, 97, 121, 108, 111, 97, 100, 129, 165, 69, 114, 114, 111, 114, 129, 176,
94
+                    73, 110, 118, 97, 108, 105, 100, 80, 97, 114, 97, 109, 101, 116, 101, 114, 192,
95
+                ],
96
+            ),
97
+        ];
98
+
99
+        for test in tests.iter() {
100
+            let mut serialized = Vec::new();
101
+            test.0
102
+                .serialize(
103
+                    &mut Serializer::new(&mut serialized)
104
+                        .with_struct_map()
105
+                        .with_string_variants(),
106
+                )
107
+                .unwrap();
108
+            let deserialized: Packet<PacketPayload> =
109
+                rmps::decode::from_slice(&serialized).unwrap();
110
+
111
+            // Test that serializing produces the expected binary results.
112
+            assert_eq!(serialized, test.1);
113
+            // Test that deserializing yields the original again.
114
+            assert_eq!(deserialized, test.0);
115
+        }
116
+    }
117
+}

+ 1
- 0
src/network/server.rs Zobrazit soubor

@@ -0,0 +1 @@
1
+

+ 138
- 0
src/protocol.rs Zobrazit soubor

@@ -0,0 +1,138 @@
1
+use serde::{Deserialize, Serialize};
2
+
3
+/*pub trait Protocol {
4
+    fn login_password(&mut self, user: &str, password: &str) -> Result<String, Error>;
5
+    fn login_app_key(&mut self, user: &str, key: &str) -> Result<(), Error>;
6
+
7
+    fn register_interest(&mut self, path: &str) -> Result<(), Error>;
8
+    fn unregister_interest(&mut self, path: &str) -> Result<(), Error>;
9
+    fn get_file_update_stream() ->
10
+
11
+    fn list_directory(path: &str) -> Result<DirectoryListing, Error>;
12
+    fn get_file_metadata(path: &str) -> Result<FileMetadata, Error>;
13
+    // TODO
14
+}*/
15
+
16
+/*pub struct DirectoryListing {
17
+    own_version: u64,
18
+    entries: Vec<FileMetadata>,
19
+    // TODO
20
+}
21
+
22
+pub struct FileMetadata {
23
+    name: String,
24
+    version: u64,
25
+    size: u64,
26
+    type_: DirectoryEntryType,
27
+}
28
+
29
+pub enum DirectoryEntryType {
30
+    Directory,
31
+    File,
32
+    SymbolicLink,
33
+}*/
34
+
35
+#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
36
+pub enum PacketPayload {
37
+    Error(Error),
38
+    ServerInfo,
39
+    ServerInfoResponse(ServerInfoResponse),
40
+    PasswordLogin(PasswordLogin),
41
+    PasswordLoginResponse(PasswordLoginResponse),
42
+    AppKeyLogin(AppKeyLogin),
43
+    AppKeyLoginResponse(AppKeyLoginResponse),
44
+    RegisterInterest(RegisterInterest),
45
+    RegisterInterestResponse(RegisterInterestResponse),
46
+    UnregisterInterest(UnregisterInterest),
47
+    UnregisterInterestResponse(UnregisterInterestResponse),
48
+    ListDirectory(ListDirectory),
49
+    ListDirectoryResponse(ListDirectoryResponse),
50
+    GetFileMetadata(GetFileMetadata),
51
+    GetFileMetadataResponse(GetFileMetadataResponse),
52
+    GetFileContent(GetFileContent),
53
+    GetFileContentResponse(GetFileContentResponse),
54
+    StartFileUpdate,
55
+    UpdateFileContent,
56
+    FinishFileUpdate,
57
+}
58
+
59
+#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
60
+pub enum Error {
61
+    InvalidParameter,
62
+}
63
+
64
+#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
65
+pub struct ServerInfoResponse {
66
+    // TODO: Version of the protocol, type of the server (encrypted/unencrypted).
67
+    pub version: String,
68
+}
69
+
70
+#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
71
+pub struct PasswordLogin {
72
+    // TODO
73
+}
74
+
75
+#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
76
+pub struct PasswordLoginResponse {
77
+    // TODO
78
+}
79
+
80
+#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
81
+pub struct AppKeyLogin {
82
+    // TODO
83
+}
84
+
85
+#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
86
+pub struct AppKeyLoginResponse {
87
+    // TODO
88
+}
89
+
90
+#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
91
+pub struct RegisterInterest {
92
+    // TODO
93
+}
94
+
95
+#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
96
+pub struct RegisterInterestResponse {
97
+    // TODO
98
+}
99
+
100
+#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
101
+pub struct UnregisterInterest {
102
+    // TODO
103
+}
104
+
105
+#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
106
+pub struct UnregisterInterestResponse {
107
+    // TODO
108
+}
109
+
110
+#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
111
+pub struct ListDirectory {
112
+    // TODO
113
+}
114
+
115
+#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
116
+pub struct ListDirectoryResponse {
117
+    // TODO
118
+}
119
+
120
+#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
121
+pub struct GetFileMetadata {
122
+    // TODO
123
+}
124
+
125
+#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
126
+pub struct GetFileMetadataResponse {
127
+    // TODO
128
+}
129
+
130
+#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
131
+pub struct GetFileContent {
132
+    // TODO
133
+}
134
+
135
+#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
136
+pub struct GetFileContentResponse {
137
+    // TODO
138
+}

Loading…
Zrušit
Uložit