diff --git a/frameworks/CSharp/beetlex/PlatformBenchmarks/DBRaw.cs b/frameworks/CSharp/beetlex/PlatformBenchmarks/DBRaw.cs index 895d2980823..c1ef0fa4722 100644 --- a/frameworks/CSharp/beetlex/PlatformBenchmarks/DBRaw.cs +++ b/frameworks/CSharp/beetlex/PlatformBenchmarks/DBRaw.cs @@ -75,8 +75,9 @@ private Fortune[] GetFortuneBuffer() public async Task LoadSingleQueryRow() { - using (var db = new NpgsqlConnection(_connectionString)) + using (var db = _dbProviderFactory.CreateConnection()) { + db.ConnectionString = _connectionString; await db.OpenAsync(); SingleCommand.Connection = db; mID.TypedValue = _random.Next(1, 10001); @@ -101,12 +102,12 @@ async Task ReadSingleRow(DbConnection connection, DbCommand cmd) public async Task> LoadMultipleQueriesRows(int count) { - using (var db = new NpgsqlConnection(_connectionString)) + using (var db = _dbProviderFactory.CreateConnection()) { + db.ConnectionString = _connectionString; await db.OpenAsync(); return await LoadMultipleRows(count, db); } - } diff --git a/frameworks/CSharp/beetlex/PlatformBenchmarks/HttpHandler.cs b/frameworks/CSharp/beetlex/PlatformBenchmarks/HttpHandler.cs index cf6f4dc643b..1c820fbcc0a 100644 --- a/frameworks/CSharp/beetlex/PlatformBenchmarks/HttpHandler.cs +++ b/frameworks/CSharp/beetlex/PlatformBenchmarks/HttpHandler.cs @@ -17,7 +17,7 @@ public partial class HttpHandler : ServerHandlerBase private static AsciiString _httpsuccess = new AsciiString("HTTP/1.1 200 OK\r\n"); - private static readonly AsciiString _headerServer = "Server: TFB\r\n"; + private static readonly AsciiString _headerServer = "Server: B\r\n"; private static readonly AsciiString _headerContentLength = "Content-Length: "; diff --git a/frameworks/CSharp/beetlex/PlatformBenchmarks/PlatformBenchmarks.csproj b/frameworks/CSharp/beetlex/PlatformBenchmarks/PlatformBenchmarks.csproj index 14958b5c5d8..d3c07772725 100644 --- a/frameworks/CSharp/beetlex/PlatformBenchmarks/PlatformBenchmarks.csproj +++ b/frameworks/CSharp/beetlex/PlatformBenchmarks/PlatformBenchmarks.csproj @@ -8,7 +8,7 @@ - + diff --git a/frameworks/Java/javalin/src/main/resources/environment.properties b/frameworks/Java/javalin/src/main/resources/environment.properties index 2a17b50e05d..46dfe9326fa 100644 --- a/frameworks/Java/javalin/src/main/resources/environment.properties +++ b/frameworks/Java/javalin/src/main/resources/environment.properties @@ -1,10 +1,10 @@ physicalTag=Citrine cloudTag=Azure -mongodbPhysicalPoolSize=200 +mongodbPhysicalPoolSize=100 mongodbCloudPoolSize=100 mongodbDefaultPoolSize=50 -postgresPhysicalPoolSize=112 +postgresPhysicalPoolSize=56 postgresCloudPoolSize=16 postgresDefaultPoolSize=10 diff --git a/frameworks/Java/redkale/benchmark_config.json b/frameworks/Java/redkale/benchmark_config.json index f299c00cb88..36f7ed31b6c 100644 --- a/frameworks/Java/redkale/benchmark_config.json +++ b/frameworks/Java/redkale/benchmark_config.json @@ -1,7 +1,7 @@ { "framework": "redkale", "tests": [{ - "default": { + "default": { "plaintext_url": "/plaintext", "json_url": "/json", "port": 8080, @@ -41,6 +41,43 @@ "display_name": "redkale", "notes": "", "versus": "Redkale" + }, + "io": { + "plaintext_url": "/plaintext", + "json_url": "/json", + "port": 8080, + "approach": "Realistic", + "classification": "Fullstack", + "database": "Postgres", + "framework": "Redkale", + "language": "Java", + "flavor": "None", + "orm": "Raw", + "platform": "Redkale", + "webserver": "Redkale", + "os": "Linux", + "database_os": "Linux", + "display_name": "redkale", + "notes": "", + "versus": "Redkale" + }, + "json": { + "json_url": "/json", + "port": 8080, + "approach": "Realistic", + "classification": "Fullstack", + "database": "Postgres", + "framework": "Redkale", + "language": "Java", + "flavor": "None", + "orm": "Raw", + "platform": "Redkale", + "webserver": "Redkale", + "os": "Linux", + "database_os": "Linux", + "display_name": "redkale", + "notes": "", + "versus": "Redkale" } }] } diff --git a/frameworks/Java/redkale/conf/application.xml b/frameworks/Java/redkale/conf/application.xml index 351d848ac8c..d4737be8dd0 100644 --- a/frameworks/Java/redkale/conf/application.xml +++ b/frameworks/Java/redkale/conf/application.xml @@ -3,19 +3,18 @@ - - + + + - - - - - + + + diff --git a/frameworks/Java/redkale/conf/persistence.xml b/frameworks/Java/redkale/conf/persistence.xml index e6e62966929..770d571c537 100644 --- a/frameworks/Java/redkale/conf/persistence.xml +++ b/frameworks/Java/redkale/conf/persistence.xml @@ -6,7 +6,8 @@ ALL - + + @@ -16,10 +17,11 @@ ALL - + + - + diff --git a/frameworks/Java/redkale/config.toml b/frameworks/Java/redkale/config.toml index a25b5621a69..1699329c1ea 100644 --- a/frameworks/Java/redkale/config.toml +++ b/frameworks/Java/redkale/config.toml @@ -29,3 +29,28 @@ orm = "Raw" platform = "Redkale" webserver = "Redkale" versus = "Redkale" + +[io] +urls.plaintext = "/plaintext" +urls.json = "/json" +approach = "Realistic" +classification = "Fullstack" +database = "None" +database_os = "Linux" +os = "Linux" +orm = "Raw" +platform = "Redkale" +webserver = "Redkale" +versus = "Redkale" + +[json] +urls.json = "/json" +approach = "Realistic" +classification = "Fullstack" +database = "None" +database_os = "Linux" +os = "Linux" +orm = "Raw" +platform = "Redkale" +webserver = "Redkale" +versus = "Redkale" diff --git a/frameworks/Java/redkale/redkale-io.dockerfile b/frameworks/Java/redkale/redkale-io.dockerfile new file mode 100644 index 00000000000..1a7dc6d87fd --- /dev/null +++ b/frameworks/Java/redkale/redkale-io.dockerfile @@ -0,0 +1,15 @@ +FROM maven:3.6.1-jdk-11-slim as maven +WORKDIR /redkale +COPY src src +COPY conf conf +COPY pom.xml pom.xml +RUN mvn package -q + +FROM openjdk:11.0.3-jdk-slim +WORKDIR /redkale +COPY conf conf +COPY --from=maven /redkale/target/redkale-benchmark-1.0.0.jar redkale-benchmark.jar + +EXPOSE 8080 + +CMD ["java", "-server", "-XX:+UseNUMA", "-XX:+UseParallelGC", "-XX:AutoBoxCacheMax=80000", "-XX:BiasedLockingStartupDelay=500", "-Dio.direct.fd=true", "-DAPP_HOME=./", "-jar", "redkale-benchmark.jar"] diff --git a/frameworks/Java/redkale/redkale-json.dockerfile b/frameworks/Java/redkale/redkale-json.dockerfile new file mode 100644 index 00000000000..3627c051146 --- /dev/null +++ b/frameworks/Java/redkale/redkale-json.dockerfile @@ -0,0 +1,15 @@ +FROM maven:3.6.1-jdk-11-slim as maven +WORKDIR /redkale +COPY src src +COPY conf conf +COPY pom.xml pom.xml +RUN mvn package -q + +FROM openjdk:11.0.3-jdk-slim +WORKDIR /redkale +COPY conf conf +COPY --from=maven /redkale/target/redkale-benchmark-1.0.0.jar redkale-benchmark.jar + +EXPOSE 8080 + +CMD ["java", "-server", "-XX:+UseNUMA", "-XX:+UseParallelGC", "-XX:AutoBoxCacheMax=80000", "-XX:BiasedLockingStartupDelay=500", "-Djson.direct.test=true", "-DAPP_HOME=./", "-jar", "redkale-benchmark.jar"] diff --git a/frameworks/Java/redkale/src/main/java/org/redkalex/benchmark/Service.java b/frameworks/Java/redkale/src/main/java/org/redkalex/benchmark/Service.java index 5cc2d66aa37..05778d480a5 100644 --- a/frameworks/Java/redkale/src/main/java/org/redkalex/benchmark/Service.java +++ b/frameworks/Java/redkale/src/main/java/org/redkalex/benchmark/Service.java @@ -13,7 +13,7 @@ import org.redkale.net.http.*; import org.redkale.service.AbstractService; import org.redkale.source.*; -import org.redkale.util.AnyValue; +import org.redkale.util.StringWrapper; /** * @@ -24,30 +24,19 @@ public class Service extends AbstractService { private static final byte[] helloBytes = "Hello, world!".getBytes(); - private final Random random = new Random(); + private final ThreadLocal localRandom = ThreadLocal.withInitial(Random::new); @Resource private DataSource source; - - @RestMapping(name = "json") - public Message getHelloMessage() { - return new Message("Hello, World!"); - } - @RestMapping(name = "plaintext") public byte[] getHelloBytes() { return helloBytes; } - @RestMapping(name = "cached-worlds") - public CachedWorld[] cachedWorlds(int q) { - final int size = Math.min(500, Math.max(1, q)); - final CachedWorld[] worlds = new CachedWorld[size]; - for (int i = 0; i < size; i++) { - worlds[i] = source.find(CachedWorld.class, randomId()); - } - return worlds; + @RestMapping(name = "json") + public Message getHelloMessage() { + return new Message("Hello, World!"); } @RestMapping(name = "db") @@ -55,23 +44,15 @@ public CompletableFuture findWorldAsync() { return source.findAsync(World.class, randomId()); } - @RestMapping(name = "fortunes") - public CompletableFuture> queryFortunes() { - return source.queryListAsync(Fortune.class).thenApply((fortunes) -> { - fortunes.add(new Fortune(0, "Additional fortune added at request time.")); - Collections.sort(fortunes); - String html = FortunesTemplate.template(fortunes).render().toString(); - return new HttpResult("text/html; charset=UTF-8", html); - }); - } - @RestMapping(name = "queries") public CompletableFuture queryWorldAsync(int q) { final int size = Math.min(500, Math.max(1, q)); + final Random random = localRandom.get(); final World[] worlds = new World[size]; + final AtomicInteger index = new AtomicInteger(); - final Function func = f -> source.findAsync(World.class, randomId()) - .thenAccept((World v) -> worlds[index.getAndIncrement()] = v); + final Function func = f -> source.findAsync(World.class, randomId(random)) + .thenAccept(v -> worlds[index.getAndIncrement()] = v); CompletableFuture future = func.apply(null); for (int i = 1; i < size; i++) { future = future.thenCompose(func); @@ -82,25 +63,54 @@ public CompletableFuture queryWorldAsync(int q) { @RestMapping(name = "updates") public CompletableFuture updateWorldAsync(int q) { final int size = Math.min(500, Math.max(1, q)); + final Random random = localRandom.get(); final World[] worlds = new World[size]; + final AtomicInteger index = new AtomicInteger(); - final Function func = f -> source.findAsync(World.class, randomId()) - .thenApply((World v) -> { - worlds[index.getAndIncrement()] = v; - v.setRandomNumber(randomId()); - return v; - }); + final Function func = f -> source.findAsync(World.class, randomId(random)) + .thenAccept(v -> worlds[index.getAndIncrement()] = v.randomNumber(randomId(random))); CompletableFuture future = func.apply(null); for (int i = 1; i < size; i++) { future = future.thenCompose(func); } - return future.thenCompose(v -> { - Arrays.sort(worlds); - return source.updateAsync(worlds); - }).thenApply(v -> worlds); + return future.thenCompose(v -> source.updateAsync(sort(worlds))).thenApply(v -> worlds); + } + + @RestMapping(name = "fortunes") + public CompletableFuture> queryFortunes() { + return source.queryListAsync(Fortune.class).thenApply((fortunes) -> { + fortunes.add(new Fortune(0, "Additional fortune added at request time.")); + String html = FortunesTemplate.template(sort(fortunes)).render().toString(); + return new HttpResult("text/html; charset=utf-8", html); + }); + } + + @RestMapping(name = "cached-worlds") + public CachedWorld[] cachedWorlds(int q) { + final int size = Math.min(500, Math.max(1, q)); + final Random random = localRandom.get(); + final CachedWorld[] worlds = new CachedWorld[size]; + for (int i = 0; i < size; i++) { + worlds[i] = source.find(CachedWorld.class, randomId(random)); + } + return worlds; + } + + private World[] sort(World[] words) { + Arrays.sort(words); + return words; + } + + private List sort(List fortunes) { + Collections.sort(fortunes); + return fortunes; } private int randomId() { + return 1 + localRandom.get().nextInt(10000); + } + + private int randomId(Random random) { return 1 + random.nextInt(10000); } } diff --git a/frameworks/Java/redkale/src/main/java/org/redkalex/benchmark/World.java b/frameworks/Java/redkale/src/main/java/org/redkalex/benchmark/World.java index ab27c3a0ba2..d32bd0b4375 100644 --- a/frameworks/Java/redkale/src/main/java/org/redkalex/benchmark/World.java +++ b/frameworks/Java/redkale/src/main/java/org/redkalex/benchmark/World.java @@ -19,6 +19,11 @@ public class World implements Comparable { private int randomNumber; + public World randomNumber(int randomNumber) { + this.randomNumber = randomNumber; + return this; + } + public int getId() { return id; } diff --git a/frameworks/PHP/kumbiaphp/benchmark_config.json b/frameworks/PHP/kumbiaphp/benchmark_config.json index 218deb63427..f1f373a2c00 100644 --- a/frameworks/PHP/kumbiaphp/benchmark_config.json +++ b/frameworks/PHP/kumbiaphp/benchmark_config.json @@ -65,7 +65,7 @@ "webserver": "None", "os": "Linux", "database_os": "Linux", - "display_name": "kumbiaphp-worker", + "display_name": "kumbiaphp-workerman", "notes": "", "versus": "workerman" }, @@ -86,7 +86,7 @@ "webserver": "None", "os": "Linux", "database_os": "Linux", - "display_name": "kumbiaphp-worker", + "display_name": "kumbiaphp-workerman-mysql", "notes": "", "versus": "workerman" } diff --git a/frameworks/PHP/phalcon/benchmark_config.json b/frameworks/PHP/phalcon/benchmark_config.json index 2c8cbf30033..69eab49bc13 100644 --- a/frameworks/PHP/phalcon/benchmark_config.json +++ b/frameworks/PHP/phalcon/benchmark_config.json @@ -40,7 +40,7 @@ "webserver": "nginx", "os": "Linux", "database_os": "Linux", - "display_name": "phalcon", + "display_name": "phalcon-mogodb", "notes": "", "versus": "php", "tags": ["broken"] @@ -62,7 +62,7 @@ "webserver": "nginx", "os": "Linux", "database_os": "Linux", - "display_name": "phalcon", + "display_name": "phalcon-micro", "notes": "", "versus": "php" } diff --git a/frameworks/PHP/php/benchmark_config.json b/frameworks/PHP/php/benchmark_config.json index 69563d56c0d..4b7a0fed988 100644 --- a/frameworks/PHP/php/benchmark_config.json +++ b/frameworks/PHP/php/benchmark_config.json @@ -87,7 +87,7 @@ "webserver": "h2o", "os": "Linux", "database_os": "Linux", - "display_name": "PHP-raw-h2o", + "display_name": "PHP-h2o", "notes": "", "versus": "php" }, @@ -133,7 +133,7 @@ "webserver": "nginx", "os": "Linux", "database_os": "Linux", - "display_name": "PHP", + "display_name": "PHP-pools", "notes": "With php-fpm pools", "versus": "php" }, @@ -173,7 +173,7 @@ "webserver": "nginx", "os": "Linux", "database_os": "Linux", - "display_name": "PHP-Eloquent", + "display_name": "PHP-laravel-query-builder", "notes": "", "versus": "php" } diff --git a/frameworks/Python/emmett/emmett.dockerfile b/frameworks/Python/emmett/emmett.dockerfile index 4d7e04c43f6..a8d9b04688b 100644 --- a/frameworks/Python/emmett/emmett.dockerfile +++ b/frameworks/Python/emmett/emmett.dockerfile @@ -1,14 +1,9 @@ -FROM python:3.7-alpine - -RUN apk add --no-cache libpq libstdc++ +FROM python:3.8 RUN mkdir -p /usr/src/app WORKDIR /usr/src/app COPY requirements.txt /usr/src/app -RUN apk add --no-cache --virtual build-deps \ - g++ libffi-dev libuv-dev make musl-dev openssl-dev postgresql-dev && \ - pip install --no-cache-dir -r /usr/src/app/requirements.txt && \ - apk del build-deps +RUN pip install --no-cache-dir -r /usr/src/app/requirements.txt COPY ./ /app WORKDIR /app diff --git a/frameworks/Python/emmett/gunicorn_conf.py b/frameworks/Python/emmett/gunicorn_conf.py index 2d45c4128fe..9583bfa63df 100644 --- a/frameworks/Python/emmett/gunicorn_conf.py +++ b/frameworks/Python/emmett/gunicorn_conf.py @@ -10,4 +10,5 @@ bind = "0.0.0.0:8080" keepalive = 120 errorlog = '-' +pidfile = '/tmp/emmett.pid' loglevel = 'error' diff --git a/frameworks/Python/emmett/requirements.txt b/frameworks/Python/emmett/requirements.txt index 8b49ed8b55e..c6fa44162d3 100644 --- a/frameworks/Python/emmett/requirements.txt +++ b/frameworks/Python/emmett/requirements.txt @@ -1,3 +1,3 @@ -emmett==2.0.0b2 -psycopg2==2.8.4 -gunicorn==19.9.0 +emmett[orjson]==2.2.0 +psycopg2-binary==2.8.6 +gunicorn==20.0.4 diff --git a/frameworks/Rust/ntex/Cargo.toml b/frameworks/Rust/ntex/Cargo.toml index a1e1b5f0e44..7e030ebdd1c 100755 --- a/frameworks/Rust/ntex/Cargo.toml +++ b/frameworks/Rust/ntex/Cargo.toml @@ -16,8 +16,8 @@ name = "ntex-raw" path = "src/main_raw.rs" [dependencies] -ntex = "0.3.3" -snmalloc-rs = { version = "0.2.24", features = ["1mib", "native-cpu"] } +ntex = "0.3.6" +snmalloc-rs = { version = "0.2.25", features = ["1mib", "native-cpu"] } yarte = { version = "0.15", features = ["bytes-buf", "json"] } env_logger = "0.8" random-fast-rng = "0.1.1" @@ -28,17 +28,13 @@ futures = "0.3.13" http = "0.2" smallvec = "1.6.1" simd-json = "0.3.24" - simd-json-derive = "0.1.15" serde = { version = "1.0", features = ["derive"] } log = { version = "0.4", features = ["release_max_level_off"] } tokio = "1" -tokio-postgres = { git="https://github.com/fafhrd91/postgres.git", branch="ntex-0.3" } +tokio-postgres = { git="https://github.com/fafhrd91/postgres.git" } [profile.release] lto = true opt-level = 3 codegen-units = 1 - -[patch.crates-io] -ntex = { git="https://github.com/ntex-rs/ntex.git", branch="tfb-0.3" } diff --git a/frameworks/Rust/ntex/src/db.rs b/frameworks/Rust/ntex/src/db.rs index 5b0ea3c5c82..f9d4b28b931 100644 --- a/frameworks/Rust/ntex/src/db.rs +++ b/frameworks/Rust/ntex/src/db.rs @@ -70,11 +70,11 @@ impl PgConnection { impl PgConnection { pub fn get_world(&self) -> impl Future { let random_id = (self.rng.borrow_mut().get_u32() % 10_000 + 1) as i32; - self.cl.query_one(&self.world, &[&random_id]).map(|row| { - let row = row.unwrap(); + self.cl.query(&self.world, &[&random_id]).map(|rows| { + let rows = rows.unwrap(); World { - id: row.get(0), - randomnumber: row.get(1), + id: rows[0].get(0), + randomnumber: rows[0].get(1), } .to_bytes::(40) }) @@ -85,17 +85,13 @@ impl PgConnection { let mut rng = self.rng.borrow_mut(); for _ in 0..num { let w_id = (rng.get_u32() % 10_000 + 1) as i32; - worlds.push( - self.cl - .query_one(&self.world, &[&w_id]) - .map(|res| match res { - Err(_) => panic!(), - Ok(row) => World { - id: row.get(0), - randomnumber: row.get(1), - }, - }), - ); + worlds.push(self.cl.query(&self.world, &[&w_id]).map(|res| { + let rows = res.unwrap(); + World { + id: rows[0].get(0), + randomnumber: rows[0].get(1), + } + })); } worlds.collect() @@ -107,17 +103,13 @@ impl PgConnection { for _ in 0..num { let id = (rng.get_u32() % 10_000 + 1) as i32; let w_id = (rng.get_u32() % 10_000 + 1) as i32; - worlds.push( - self.cl - .query_one(&self.world, &[&w_id]) - .map(move |res| match res { - Err(_) => panic!(), - Ok(row) => World { - id: row.get(0), - randomnumber: id, - }, - }), - ); + worlds.push(self.cl.query(&self.world, &[&w_id]).map(move |res| { + let rows = res.unwrap(); + World { + id: rows[0].get(0), + randomnumber: id, + } + })); } let cl = self.cl.clone(); @@ -146,14 +138,13 @@ impl PgConnection { let fut = self.cl.query_raw(&self.fortune, &[]); async move { - let mut stream = fut.await.unwrap(); + let rows = fut.await.unwrap(); let mut fortunes: SmallVec<[_; 32]> = smallvec::smallvec![Fortune { id: 0, message: Cow::Borrowed("Additional fortune added at request time."), }]; - while let Some(row) = stream.next().await { - let row = row.unwrap(); + for row in rows { fortunes.push(Fortune { id: row.get(0), message: Cow::Owned(row.get(1)), diff --git a/frameworks/Rust/ntex/src/main.rs b/frameworks/Rust/ntex/src/main.rs index f5df61c15e8..44790dd9457 100644 --- a/frameworks/Rust/ntex/src/main.rs +++ b/frameworks/Rust/ntex/src/main.rs @@ -47,6 +47,8 @@ async fn main() -> std::io::Result<()> { .keep_alive(http::KeepAlive::Os) .client_timeout(0) .disconnect_timeout(0) + .read_high_watermark(65535) + .write_high_watermark(65535) .h1(web::App::new() .service(json) .service(plaintext) diff --git a/frameworks/Rust/ntex/src/main_db.rs b/frameworks/Rust/ntex/src/main_db.rs index 4c5fd81c921..809d84a8c91 100644 --- a/frameworks/Rust/ntex/src/main_db.rs +++ b/frameworks/Rust/ntex/src/main_db.rs @@ -99,6 +99,8 @@ async fn main() -> std::io::Result<()> { .keep_alive(KeepAlive::Os) .client_timeout(0) .disconnect_timeout(0) + .read_high_watermark(65535) + .write_high_watermark(65535) .h1(AppFactory) .tcp() })? diff --git a/frameworks/Rust/ntex/src/main_raw.rs b/frameworks/Rust/ntex/src/main_raw.rs index ab8a4d741a6..c3cd84c40c4 100644 --- a/frameworks/Rust/ntex/src/main_raw.rs +++ b/frameworks/Rust/ntex/src/main_raw.rs @@ -43,25 +43,33 @@ impl Future for App { loop { match this.state.decode_item(&this.codec) { Ok(Some((req, _))) => { - match req.path() { - "/json" => this.state.with_write_buf(|buf| { - buf.extend_from_slice(JSON); - this.codec.set_date_header(buf); - Message { - message: "Hello, World!", + this.state.with_write_buf(|buf| { + // make sure we've got room + let remaining = buf.capacity() - buf.len(); + if remaining < 1024 { + buf.reserve(65535 - remaining); + } + + match req.path() { + "/json" => { + buf.extend_from_slice(JSON); + this.codec.set_date_header(buf); + Message { + message: "Hello, World!", + } + .to_bytes_mut(buf); + } + "/plaintext" => { + buf.extend_from_slice(PLAIN); + this.codec.set_date_header(buf); + buf.extend_from_slice(BODY); } - .to_bytes_mut(buf); - }), - "/plaintext" => this.state.with_write_buf(|buf| { - buf.extend_from_slice(PLAIN); - this.codec.set_date_header(buf); - buf.extend_from_slice(BODY); - }), - _ => this.state.with_write_buf(|buf| { - buf.extend_from_slice(HTTPNFOUND); - buf.extend_from_slice(HDR_SERVER); - }), - } + _ => { + buf.extend_from_slice(HTTPNFOUND); + buf.extend_from_slice(HDR_SERVER); + } + } + }); updated = true; } Ok(None) => break, @@ -74,10 +82,10 @@ impl Future for App { if updated { this.state.dsp_restart_write_task(); } - if !this.state.is_read_ready() { - this.state.dsp_read_more_data(cx.waker()); - } else { + if this.state.is_read_ready() { this.state.dsp_register_task(cx.waker()); + } else { + this.state.dsp_read_more_data(cx.waker()); } Poll::Pending } @@ -92,7 +100,7 @@ async fn main() -> io::Result<()> { .backlog(1024) .bind("techempower", "0.0.0.0:8080", || { fn_service(|io: TcpStream| { - let state = State::new().disconnect_timeout(0); + let state = State::with_params(65535, 65535, 1024, 0); let io = Rc::new(RefCell::new(io)); ntex::rt::spawn(ReadTask::new(io.clone(), state.clone())); ntex::rt::spawn(WriteTask::new(io, state.clone())); diff --git a/frameworks/Rust/salvo/Cargo.toml b/frameworks/Rust/salvo/Cargo.toml new file mode 100644 index 00000000000..b653e2bf7c6 --- /dev/null +++ b/frameworks/Rust/salvo/Cargo.toml @@ -0,0 +1,46 @@ +[package] +name = "salvo_test" +version = "0.6.5" +edition = "2018" + +[[bin]] +name = "main" +path = "src/main.rs" + +[[bin]] +name = "main-db" +path = "src/main_db.rs" + +[[bin]] +name = "main-pg" +path = "src/main_pg.rs" + +[dependencies] +anyhow = "1.0.38" +askama = "0.8" +diesel = { version = "1.4.3", features = ["postgres", "r2d2"] } +salvo = { version = "0.7.0", features = ["anyhow"] } +tokio = { version = "1.2", features = ["full"] } +snmalloc-rs = { version = "0.2.24", features = ["1mib", "native-cpu"] } +random-fast-rng = "0.1.1" +futures = "0.3.12" +smallvec = "1.6.1" +simd-json = "0.3" +simd-json-derive = "0.1.15" +serde = { version = "1.0", features = ["derive"] } +tokio-postgres = "0.7" +yarte = { version = "0.15", features = ["bytes-buf"] } +once_cell = "1.5.2" +rand = { version = "0.8.3", features = ["small_rng"] } +hyper = "0.14.4" + +[profile.release] +lto = true +opt-level = 3 +codegen-units = 1 + +# [patch.crates-io] +# salvo = { path = "D:/Kenorld/salvo-rs/salvo" } +# salvo_core = { path = "D:/Kenorld/salvo-rs/salvo/core" } +# salvo_macros = { path = "D:/Kenorld/salvo-rs/salvo/macros" } +# salvo_extra = { path = "D:/Kenorld/salvo-rs/salvo/extra" } diff --git a/frameworks/Rust/salvo/README.md b/frameworks/Rust/salvo/README.md new file mode 100644 index 00000000000..d56b2c208c6 --- /dev/null +++ b/frameworks/Rust/salvo/README.md @@ -0,0 +1,5 @@ +# [salvo](https://salvo.rs) web framework + +## Description + +A easy to use web framework written by rust. diff --git a/frameworks/Rust/salvo/benchmark_config.json b/frameworks/Rust/salvo/benchmark_config.json new file mode 100644 index 00000000000..592821a4967 --- /dev/null +++ b/frameworks/Rust/salvo/benchmark_config.json @@ -0,0 +1,66 @@ +{ + "framework": "salvo", + "tests": [ + { + "default": { + "json_url": "/json", + "plaintext_url": "/plaintext", + "port": 8080, + "approach": "Realistic", + "classification": "Micro", + "database": "postgres", + "framework": "salvo", + "language": "Rust", + "flavor": "None", + "orm": "Micro", + "platform": "None", + "webserver": "None", + "os": "Linux", + "database_os": "Linux", + "display_name": "Salvo", + "notes": "", + "versus": "None" + }, + "db": { + "db_url": "/db", + "fortune_url": "/fortunes", + "query_url": "/queries?q=", + "update_url": "/updates?q=", + "port": 8080, + "approach": "Realistic", + "classification": "Micro", + "database": "Postgres", + "framework": "salvo", + "language": "Rust", + "orm": "Raw", + "platform": "None", + "webserver": "None", + "os": "Linux", + "database_os": "Linux", + "display_name": "Salvo [Diesel]", + "notes": "", + "versus": "" + }, + "pg": { + "db_url": "/db", + "fortune_url": "/fortunes", + "query_url": "/queries?q=", + "update_url": "/updates?q=", + "port": 8080, + "approach": "Realistic", + "classification": "Micro", + "database": "Postgres", + "framework": "salvo", + "language": "Rust", + "orm": "Raw", + "platform": "None", + "webserver": "None", + "os": "Linux", + "database_os": "Linux", + "display_name": "Salvo [PG]", + "notes": "", + "versus": "" + } + } + ] +} diff --git a/frameworks/Rust/salvo/config.toml b/frameworks/Rust/salvo/config.toml new file mode 100644 index 00000000000..04edbc3b0de --- /dev/null +++ b/frameworks/Rust/salvo/config.toml @@ -0,0 +1,43 @@ +[framework] +name = "salvo" + +[main] +urls.plaintext = "/plaintext" +urls.json = "/json" +approach = "Realistic" +classification = "Micro" +database = "Postgres" +database_os = "Linux" +os = "Linux" +orm = "Raw" +platform = "None" +webserver = "salvo" +versus = "" + +[db] +urls.db = "/db" +urls.query = "/query?q=" +urls.update = "/update?q=" +urls.fortune = "/fortunes" +approach = "Realistic" +classification = "Micro" +database = "Postgres" +database_os = "Linux" +os = "Linux" +orm = "Raw" +platform = "None" +webserver = "salvo" +versus = "" + +[raw] +urls.plaintext = "/plaintext" +urls.json = "/json" +approach = "Realistic" +classification = "Platform" +database = "Postgres" +database_os = "Linux" +os = "Linux" +orm = "Raw" +platform = "None" +webserver = "salvo" +versus = "" diff --git a/frameworks/Rust/salvo/rustfmt.toml b/frameworks/Rust/salvo/rustfmt.toml new file mode 100644 index 00000000000..237a52a10c8 --- /dev/null +++ b/frameworks/Rust/salvo/rustfmt.toml @@ -0,0 +1,2 @@ +max_width = 120 +reorder_imports = true diff --git a/frameworks/Rust/salvo/salvo-db.dockerfile b/frameworks/Rust/salvo/salvo-db.dockerfile new file mode 100644 index 00000000000..a2c63b5a792 --- /dev/null +++ b/frameworks/Rust/salvo/salvo-db.dockerfile @@ -0,0 +1,13 @@ +FROM rust:1.50 + +RUN apt-get update -yqq && apt-get install -yqq cmake g++ + +ADD ./ /salvo +WORKDIR /salvo + +RUN cargo clean +RUN RUSTFLAGS="-C target-cpu=native" cargo build --release + +EXPOSE 8080 + +CMD ./target/release/main-db diff --git a/frameworks/Rust/salvo/salvo-pg.dockerfile b/frameworks/Rust/salvo/salvo-pg.dockerfile new file mode 100644 index 00000000000..64b10a08653 --- /dev/null +++ b/frameworks/Rust/salvo/salvo-pg.dockerfile @@ -0,0 +1,13 @@ +FROM rust:1.50 + +RUN apt-get update -yqq && apt-get install -yqq cmake g++ + +ADD ./ /salvo +WORKDIR /salvo + +RUN cargo clean +RUN RUSTFLAGS="-C target-cpu=native" cargo build --release + +EXPOSE 8080 + +CMD ./target/release/main-pg diff --git a/frameworks/Rust/salvo/salvo.dockerfile b/frameworks/Rust/salvo/salvo.dockerfile new file mode 100644 index 00000000000..9be27fa3807 --- /dev/null +++ b/frameworks/Rust/salvo/salvo.dockerfile @@ -0,0 +1,16 @@ +FROM rust:1.50 + +# Disable simd at jsonescape +ENV CARGO_CFG_JSONESCAPE_DISABLE_AUTO_SIMD= + +RUN apt-get update -yqq && apt-get install -yqq cmake g++ + +ADD ./ /salvo +WORKDIR /salvo + +RUN cargo clean +RUN RUSTFLAGS="-C target-cpu=native" cargo build --release + +EXPOSE 8080 + +CMD ./target/release/main diff --git a/frameworks/Rust/salvo/src/main.rs b/frameworks/Rust/salvo/src/main.rs new file mode 100644 index 00000000000..63a720a4e5d --- /dev/null +++ b/frameworks/Rust/salvo/src/main.rs @@ -0,0 +1,41 @@ +#[global_allocator] +static ALLOC: snmalloc_rs::SnMalloc = snmalloc_rs::SnMalloc; + +use salvo::http::header::{self, HeaderValue}; +use salvo::prelude::*; +use simd_json_derive::Serialize; +use hyper::server::conn::AddrIncoming; + +static HELLO_WORLD: &'static [u8] = b"Hello, world!"; +#[derive(Serialize)] +pub struct Message { + pub message: &'static str, +} + +#[fn_handler] +async fn json(res: &mut Response) { + res.headers_mut().insert(header::SERVER, HeaderValue::from_static("S")); + let msg = Message { + message: "Hello, World!", + }; + res.render_binary(HeaderValue::from_static("application/json"), &msg.json_vec().unwrap()); +} + +#[fn_handler] +async fn plaintext(res: &mut Response) { + res.headers_mut().insert(header::SERVER, HeaderValue::from_static("S")); + res.render_binary(HeaderValue::from_static("text/plain"), HELLO_WORLD); +} + +#[tokio::main] +async fn main() { + println!("Started http server: 127.0.0.1:8080"); + let router = Router::new() + .push(Router::new().path("plaintext").get(plaintext)) + .push(Router::new().path("json").get(json)); + // Server::new(router).bind(([0, 0, 0, 0], 8080)).await; + + let mut incoming = AddrIncoming::bind(&(([0, 0, 0, 0], 8080)).into()).unwrap(); + incoming.set_nodelay(true); + Server::builder(incoming).http1_pipeline_flush(true).serve(Service::new(router)).await.unwrap(); +} diff --git a/frameworks/Rust/salvo/src/main_db.rs b/frameworks/Rust/salvo/src/main_db.rs new file mode 100644 index 00000000000..32393a0ac22 --- /dev/null +++ b/frameworks/Rust/salvo/src/main_db.rs @@ -0,0 +1,134 @@ +#[global_allocator] +static ALLOC: snmalloc_rs::SnMalloc = snmalloc_rs::SnMalloc; + +#[macro_use] +extern crate diesel; + +use anyhow::Error; +use askama::Template; +use diesel::prelude::*; +use diesel::r2d2::{ConnectionManager, Pool, PoolError, PooledConnection}; +use once_cell::sync::OnceCell; +use rand::rngs::SmallRng; +use rand::{Rng, SeedableRng}; +use salvo::http::header::{self, HeaderValue}; +use salvo::prelude::*; +use std::{cmp, io}; + +mod models; +mod schema; +use models::*; +use schema::*; + +const DB_URL: &str = "postgres://benchmarkdbuser:benchmarkdbpass@tfb-database/hello_world"; +pub type PgPool = Pool>; + +pub static DB_POOL: OnceCell = OnceCell::new(); + +pub fn connect() -> Result>, PoolError> { + DB_POOL.get().unwrap().get() +} +pub fn build_pool(database_url: &str) -> Result { + let manager = ConnectionManager::::new(database_url); + diesel::r2d2::Pool::builder().max_size(50).build(manager) +} + +#[fn_handler] +async fn world_row(_req: &mut Request, res: &mut Response) -> Result<(), Error> { + let mut rng = SmallRng::from_entropy(); + let random_id = rng.gen_range(1..10_001); + let conn = connect()?; + let row = world::table.find(random_id).first::(&conn)?; + res.headers_mut().insert(header::SERVER, HeaderValue::from_static("S")); + res.render_json(&row); + Ok(()) +} + +#[fn_handler] +async fn queries(req: &mut Request, res: &mut Response) -> Result<(), Error> { + let count = req.get_query::("q").unwrap_or(1); + let count = cmp::min(500, cmp::max(1, count)); + + let mut worlds = Vec::with_capacity(count); + let mut rng = SmallRng::from_entropy(); + let conn = connect()?; + for _ in 0..count { + let id = rng.gen_range(1..10_001); + let w = world::table.find(id).get_result::(&conn)?; + worlds.push(w); + } + res.headers_mut().insert(header::SERVER, HeaderValue::from_static("S")); + res.render_json(&worlds); + Ok(()) +} +#[fn_handler] +async fn updates(req: &mut Request, res: &mut Response) -> Result<(), Error> { + let count = req.get_query::("q").unwrap_or(1); + let count = cmp::min(500, cmp::max(1, count)); + + let conn = connect()?; + let mut worlds = Vec::with_capacity(count); + let mut rng = SmallRng::from_entropy(); + for _ in 0..count { + let w_id: i32 = rng.gen_range(1..10_001); + let mut w = world::table.find(w_id).first::(&conn)?; + w.randomnumber = rng.gen_range(1..10_001); + worlds.push(w); + } + worlds.sort_by_key(|w| w.id); + conn.transaction::<(), Error, _>(|| { + for w in &worlds { + diesel::update(world::table) + .filter(world::id.eq(w.id)) + .set(world::randomnumber.eq(w.randomnumber)) + .execute(&conn)?; + } + Ok(()) + })?; + + res.headers_mut().insert(header::SERVER, HeaderValue::from_static("S")); + res.render_json(&worlds); + Ok(()) +} + +#[derive(Template)] +#[template(path = "fortune.html")] +struct FortuneTemplate<'a> { + items: &'a Vec, +} + +#[fn_handler] +async fn fortunes(_req: &mut Request, res: &mut Response) -> Result<(), Error> { + let conn = connect()?; + let rows = match fortune::table.get_results::(&conn) { + Ok(mut items) => { + items.push(Fortune { + id: 0, + message: "Additional fortune added at request time.".to_string(), + }); + items.sort_by(|it, next| it.message.cmp(&next.message)); + Ok(items) + } + Err(e) => Err(io::Error::new(io::ErrorKind::Other, e)), + }?; + let tmpl = FortuneTemplate { items: &rows }; + res.headers_mut().insert(header::SERVER, HeaderValue::from_static("S")); + res.render_html_text(&tmpl.render().unwrap()); + Ok(()) +} + +#[tokio::main] +async fn main() { + println!("Starting http server: 127.0.0.1:8080"); + + DB_POOL + .set(build_pool(&DB_URL).expect(&format!("Error connecting to {}", &DB_URL))) + .ok(); + + let router = Router::new() + .push(Router::new().path("db").get(world_row)) + .push(Router::new().path("fortunes").get(fortunes)) + .push(Router::new().path("queries").get(queries)) + .push(Router::new().path("updates").get(updates)); + Server::new(router).bind(([0, 0, 0, 0], 8080)).await; +} diff --git a/frameworks/Rust/salvo/src/main_pg.rs b/frameworks/Rust/salvo/src/main_pg.rs new file mode 100644 index 00000000000..d535888a608 --- /dev/null +++ b/frameworks/Rust/salvo/src/main_pg.rs @@ -0,0 +1,198 @@ +#[global_allocator] +static ALLOC: snmalloc_rs::SnMalloc = snmalloc_rs::SnMalloc; + +use anyhow::Error; +use futures::{pin_mut, TryStreamExt}; +use once_cell::sync::OnceCell; +use rand::rngs::SmallRng; +use rand::{Rng, SeedableRng}; +use salvo::http::header::{self, HeaderValue}; +use salvo::prelude::*; +use serde::Serialize; +use std::borrow::Cow; +use std::collections::HashMap; +use std::fmt::Write; +use std::{cmp, io}; +use tokio_postgres::types::ToSql; +use tokio_postgres::{self, Client, NoTls, Statement}; +use yarte::ywrite_html; + +mod models; +use models::*; + +const DB_URL: &str = "postgres://benchmarkdbuser:benchmarkdbpass@tfb-database/hello_world"; +pub static DB_CONN: OnceCell = OnceCell::new(); +pub fn connect() -> &'static PgConnection { + DB_CONN.get().unwrap() +} +pub struct PgConnection { + client: Client, + fortune: Statement, + world: Statement, + updates: HashMap, +} + +#[derive(Serialize, Debug)] +pub struct CowFortune { + pub id: i32, + pub message: Cow<'static, str>, +} + +impl PgConnection { + pub async fn connect(db_url: &str) -> Result { + let (client, conn) = tokio_postgres::connect(db_url, NoTls) + .await + .expect("can not connect to postgresql"); + tokio::spawn(async move { + if let Err(e) = conn.await { + eprintln!("connection error: {}", e); + } + }); + + let fortune = client.prepare("SELECT * FROM fortune").await.unwrap(); + let world = client.prepare("SELECT * FROM world WHERE id=$1").await.unwrap(); + let mut updates_statements = HashMap::new(); + for num in 1..=500u16 { + let mut pl: u16 = 1; + let mut q = String::new(); + q.push_str("UPDATE world SET randomnumber = CASE id "); + for _ in 1..=num { + let _ = write!(&mut q, "when ${} then ${} ", pl, pl + 1); + pl += 2; + } + q.push_str("ELSE randomnumber END WHERE id IN ("); + for _ in 1..=num { + let _ = write!(&mut q, "${},", pl); + pl += 1; + } + q.pop(); + q.push(')'); + updates_statements.insert(num, client.prepare(&q).await.unwrap()); + } + + Ok(PgConnection { + client, + fortune, + world, + updates: updates_statements, + }) + } +} + +#[fn_handler] +async fn world_row(_req: &mut Request, res: &mut Response) -> Result<(), Error> { + let conn = connect(); + let mut rng = SmallRng::from_entropy(); + let random_id = (rng.gen::() % 10_000 + 1) as i32; + let row = conn.client.query_one(&conn.world, &[&random_id]).await?; + res.headers_mut().insert(header::SERVER, HeaderValue::from_static("S")); + let world = &World { + id: row.get(0), + randomnumber: row.get(1), + }; + res.render_json(&world); + Ok(()) +} + +#[fn_handler] +async fn queries(req: &mut Request, res: &mut Response) -> Result<(), Error> { + let count = req.get_query::("q").unwrap_or(1); + let count = cmp::min(500, cmp::max(1, count)); + + let mut worlds = Vec::with_capacity(count); + let mut rng = SmallRng::from_entropy(); + let conn = connect(); + for _ in 0..count { + let w_id = (rng.gen::() % 10_000 + 1) as i32; + let row = conn.client.query_one(&conn.world, &[&w_id]).await?; + worlds.push(World { + id: row.get(0), + randomnumber: row.get(1), + }); + } + res.headers_mut().insert(header::SERVER, HeaderValue::from_static("S")); + res.render_json(&worlds); + Ok(()) +} + +#[fn_handler] +async fn updates(req: &mut Request, res: &mut Response) -> Result<(), Error> { + let count = req.get_query::("q").unwrap_or(1); + let count = cmp::min(500, cmp::max(1, count)); + + let mut worlds = Vec::with_capacity(count); + let mut rng = SmallRng::from_entropy(); + let conn = connect(); + for _ in 0..count { + let id = (rng.gen::() % 10_000 + 1) as i32; + let w_id = (rng.gen::() % 10_000 + 1) as i32; + let row = conn.client.query_one(&conn.world, &[&w_id]).await?; + worlds.push(World { + id: row.get(0), + randomnumber: id, + }); + } + + let st = conn.updates.get(&(count as u16)).unwrap().clone(); + + let mut params: Vec<&(dyn ToSql + std::marker::Sync)> = Vec::with_capacity(count * 3); + for w in &worlds { + params.push(&w.id); + params.push(&w.randomnumber); + } + for w in &worlds { + params.push(&w.id); + } + + conn.client.query(&st, ¶ms).await?; + res.headers_mut().insert(header::SERVER, HeaderValue::from_static("S")); + res.render_json(&worlds); + Ok(()) +} + +#[fn_handler] +async fn fortunes(_req: &mut Request, res: &mut Response) -> Result<(), Error> { + let mut items = vec![CowFortune { + id: 0, + message: Cow::Borrowed("Additional fortune added at request time."), + }]; + let conn = connect(); + let params: [&str; 0] = []; + let stream = conn.client.query_raw(&conn.fortune, ¶ms).await?; + pin_mut!(stream); + + while let Some(row) = stream.try_next().await? { + items.push(CowFortune { + id: row.get(0), + message: Cow::Owned(row.get(1)), + }); + } + + items.sort_by(|it, next| it.message.cmp(&next.message)); + + let mut body = Vec::with_capacity(2048); + ywrite_html!(body, "{{> fortune }}"); + + res.headers_mut().insert(header::SERVER, HeaderValue::from_static("S")); + res.render_binary("text/html; charset=utf-8".parse().unwrap(), &body); + Ok(()) +} + +#[tokio::main] +async fn main() { + println!("Started http server: 127.0.0.1:8080"); + + DB_CONN + .set( + PgConnection::connect(DB_URL) + .await + .expect(&format!("Error connecting to {}", &DB_URL)), + ) + .ok(); + let router = Router::new() + .push(Router::new().path("db").get(world_row)) + .push(Router::new().path("fortunes").get(fortunes)) + .push(Router::new().path("queries").get(queries)) + .push(Router::new().path("updates").get(updates)); + Server::new(router).bind(([0, 0, 0, 0], 8080)).await; +} diff --git a/frameworks/Rust/salvo/src/models.rs b/frameworks/Rust/salvo/src/models.rs new file mode 100644 index 00000000000..54abd157065 --- /dev/null +++ b/frameworks/Rust/salvo/src/models.rs @@ -0,0 +1,21 @@ +use diesel::Queryable; +use serde::{Deserialize, Serialize}; + +#[derive(Serialize, Deserialize)] +pub struct Message { + pub message: &'static str, +} + +#[allow(non_snake_case)] +#[derive(Serialize, Queryable, Debug)] +pub struct World { + pub id: i32, + pub randomnumber: i32, +} + +#[allow(non_snake_case)] +#[derive(Serialize, Queryable, Debug)] +pub struct Fortune { + pub id: i32, + pub message: String, +} diff --git a/frameworks/Rust/salvo/src/schema.rs b/frameworks/Rust/salvo/src/schema.rs new file mode 100644 index 00000000000..30b1bfeb7fc --- /dev/null +++ b/frameworks/Rust/salvo/src/schema.rs @@ -0,0 +1,13 @@ +table! { + world (id) { + id -> Integer, + randomnumber -> Integer, + } +} + +table! { + fortune (id) { + id -> Integer, + message -> Text, + } +} diff --git a/frameworks/Rust/salvo/templates/fortune.hbs b/frameworks/Rust/salvo/templates/fortune.hbs new file mode 100644 index 00000000000..c6d72bca4a4 --- /dev/null +++ b/frameworks/Rust/salvo/templates/fortune.hbs @@ -0,0 +1,5 @@ +Fortunes + {{~# each items ~}} + + {{~/each ~}} +
idmessage
{{id}}{{message}}
diff --git a/frameworks/Rust/salvo/templates/fortune.html b/frameworks/Rust/salvo/templates/fortune.html new file mode 100644 index 00000000000..7c448b9d999 --- /dev/null +++ b/frameworks/Rust/salvo/templates/fortune.html @@ -0,0 +1,12 @@ + + + Fortunes + + + + {% for item in items %} + + {% endfor %} +
idmessage
{{item.id}}{{item.message}}
+ + diff --git a/frameworks/Rust/tide/Cargo.lock b/frameworks/Rust/tide/Cargo.lock new file mode 100644 index 00000000000..6d7624293fd --- /dev/null +++ b/frameworks/Rust/tide/Cargo.lock @@ -0,0 +1,1931 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +[[package]] +name = "aead" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fc95d1bdb8e6666b2b217308eeeb09f2d6728d104be3e31916cc74d15420331" +dependencies = [ + "generic-array", +] + +[[package]] +name = "aes" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "884391ef1066acaa41e766ba8f596341b96e93ce34f9a43e7d24bf0a0eaf0561" +dependencies = [ + "aes-soft", + "aesni", + "cipher", +] + +[[package]] +name = "aes-gcm" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5278b5fabbb9bd46e24aa69b2fdea62c99088e0a950a9be40e3e0101298f88da" +dependencies = [ + "aead", + "aes", + "cipher", + "ctr", + "ghash", + "subtle", +] + +[[package]] +name = "aes-soft" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be14c7498ea50828a38d0e24a765ed2effe92a705885b57d029cd67d45744072" +dependencies = [ + "cipher", + "opaque-debug", +] + +[[package]] +name = "aesni" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea2e11f5e94c2f7d386164cc2aa1f97823fed6f259e486940a71c174dd01b0ce" +dependencies = [ + "cipher", + "opaque-debug", +] + +[[package]] +name = "anyhow" +version = "1.0.38" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "afddf7f520a80dbf76e6f50a35bca42a2331ef227a28b3b6dc5c2e2338d114b1" + +[[package]] +name = "arrayref" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4c527152e37cf757a3f78aae5a06fbeefdb07ccc535c980a3208ee3060dd544" + +[[package]] +name = "arrayvec" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b" + +[[package]] +name = "askama" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d298738b6e47e1034e560e5afe63aa488fea34e25ec11b855a76f0d7b8e73134" +dependencies = [ + "askama_derive", + "askama_escape", + "askama_shared", +] + +[[package]] +name = "askama_derive" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca2925c4c290382f9d2fa3d1c1b6a63fa1427099721ecca4749b154cc9c25522" +dependencies = [ + "askama_shared", + "proc-macro2", + "syn", +] + +[[package]] +name = "askama_escape" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90c108c1a94380c89d2215d0ac54ce09796823cca0fd91b299cfff3b33e346fb" + +[[package]] +name = "askama_shared" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2582b77e0f3c506ec4838a25fa8a5f97b9bed72bb6d3d272ea1c031d8bd373bc" +dependencies = [ + "askama_escape", + "humansize", + "nom", + "num-traits", + "percent-encoding", + "proc-macro2", + "quote", + "serde", + "syn", + "toml", +] + +[[package]] +name = "async-attributes" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3203e79f4dd9bdda415ed03cf14dae5a2bf775c683a00f94e9cd1faf0f596e5" +dependencies = [ + "quote", + "syn", +] + +[[package]] +name = "async-channel" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2114d64672151c0c5eaa5e131ec84a74f06e1e559830dabba01ca30605d66319" +dependencies = [ + "concurrent-queue", + "event-listener", + "futures-core", +] + +[[package]] +name = "async-dup" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7427a12b8dc09291528cfb1da2447059adb4a257388c2acd6497a79d55cf6f7c" +dependencies = [ + "futures-io", + "simple-mutex", +] + +[[package]] +name = "async-executor" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb877970c7b440ead138f6321a3b5395d6061183af779340b65e20c0fede9146" +dependencies = [ + "async-task", + "concurrent-queue", + "fastrand", + "futures-lite", + "once_cell", + "vec-arena", +] + +[[package]] +name = "async-global-executor" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9586ec52317f36de58453159d48351bc244bc24ced3effc1fce22f3d48664af6" +dependencies = [ + "async-channel", + "async-executor", + "async-io", + "async-mutex", + "blocking", + "futures-lite", + "num_cpus", + "once_cell", +] + +[[package]] +name = "async-h1" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e9e2a9745d9cd0d92ed7641ce4d07568985762f92633260f0afe8ac7917d9d7" +dependencies = [ + "async-channel", + "async-dup", + "async-std", + "byte-pool", + "futures-core", + "http-types", + "httparse", + "lazy_static", + "log", + "pin-project", +] + +[[package]] +name = "async-io" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9315f8f07556761c3e48fec2e6b276004acf426e6dc068b2c2251854d65ee0fd" +dependencies = [ + "concurrent-queue", + "fastrand", + "futures-lite", + "libc", + "log", + "nb-connect", + "once_cell", + "parking", + "polling", + "vec-arena", + "waker-fn", + "winapi", +] + +[[package]] +name = "async-lock" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1996609732bde4a9988bc42125f55f2af5f3c36370e27c778d5191a4a1b63bfb" +dependencies = [ + "event-listener", +] + +[[package]] +name = "async-mutex" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "479db852db25d9dbf6204e6cb6253698f175c15726470f78af0d918e99d6156e" +dependencies = [ + "event-listener", +] + +[[package]] +name = "async-process" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef37b86e2fa961bae5a4d212708ea0154f904ce31d1a4a7f47e1bbc33a0c040b" +dependencies = [ + "async-io", + "blocking", + "cfg-if 1.0.0", + "event-listener", + "futures-lite", + "once_cell", + "signal-hook", + "winapi", +] + +[[package]] +name = "async-session" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "345022a2eed092cd105cc1b26fd61c341e100bd5fcbbd792df4baf31c2cc631f" +dependencies = [ + "anyhow", + "async-std", + "async-trait", + "base64 0.12.3", + "bincode", + "blake3", + "chrono", + "hmac 0.8.1", + "kv-log-macro", + "rand", + "serde", + "serde_json", + "sha2", +] + +[[package]] +name = "async-sse" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53bba003996b8fd22245cd0c59b869ba764188ed435392cf2796d03b805ade10" +dependencies = [ + "async-channel", + "async-std", + "http-types", + "log", + "memchr", + "pin-project-lite 0.1.11", +] + +[[package]] +name = "async-std" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9f06685bad74e0570f5213741bea82158279a4103d988e57bfada11ad230341" +dependencies = [ + "async-attributes", + "async-channel", + "async-global-executor", + "async-io", + "async-lock", + "async-process", + "crossbeam-utils 0.8.3", + "futures-channel", + "futures-core", + "futures-io", + "futures-lite", + "gloo-timers", + "kv-log-macro", + "log", + "memchr", + "num_cpus", + "once_cell", + "pin-project-lite 0.2.4", + "pin-utils", + "slab", + "wasm-bindgen-futures", +] + +[[package]] +name = "async-task" +version = "4.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e91831deabf0d6d7ec49552e489aed63b7456a7a3c46cff62adad428110b0af0" + +[[package]] +name = "async-trait" +version = "0.1.42" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d3a45e77e34375a7923b1e8febb049bb011f064714a8e17a1a616fef01da13d" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "atomic-waker" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "065374052e7df7ee4047b1160cca5e1467a12351a40b3da123c870ba0b8eda2a" + +[[package]] +name = "autocfg" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" + +[[package]] +name = "base-x" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4521f3e3d031370679b3b140beb36dfe4801b09ac77e30c61941f97df3ef28b" + +[[package]] +name = "base64" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3441f0f7b02788e948e47f457ca01f1d7e6d92c693bc132c22b087d3141c03ff" + +[[package]] +name = "base64" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" + +[[package]] +name = "bincode" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f30d3a39baa26f9651f17b375061f3233dde33424a8b72b0dbe93a68a0bc896d" +dependencies = [ + "byteorder", + "serde", +] + +[[package]] +name = "bitflags" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" + +[[package]] +name = "bitvec" +version = "0.19.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7ba35e9565969edb811639dbebfe34edc0368e472c5018474c8eb2543397f81" +dependencies = [ + "funty", + "radium", + "tap", + "wyz", +] + +[[package]] +name = "blake3" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e9ff35b701f3914bdb8fad3368d822c766ef2858b2583198e41639b936f09d3f" +dependencies = [ + "arrayref", + "arrayvec", + "cc", + "cfg-if 0.1.10", + "constant_time_eq", + "crypto-mac 0.8.0", + "digest", +] + +[[package]] +name = "block-buffer" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" +dependencies = [ + "generic-array", +] + +[[package]] +name = "blocking" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c5e170dbede1f740736619b776d7251cb1b9095c435c34d8ca9f57fcd2f335e9" +dependencies = [ + "async-channel", + "async-task", + "atomic-waker", + "fastrand", + "futures-lite", + "once_cell", +] + +[[package]] +name = "bumpalo" +version = "3.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63396b8a4b9de3f4fdfb320ab6080762242f66a8ef174c49d8e19b674db4cdbe" + +[[package]] +name = "byte-pool" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38e98299d518ec351ca016363e0cbfc77059dcd08dfa9700d15e405536097a" +dependencies = [ + "crossbeam-queue", + "stable_deref_trait", +] + +[[package]] +name = "byteorder" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae44d1a3d5a19df61dd0c8beb138458ac2a53a7ac09eba97d55592540004306b" + +[[package]] +name = "cache-padded" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "631ae5198c9be5e753e5cc215e1bd73c2b466a3565173db433f52bb9d3e66dba" + +[[package]] +name = "cc" +version = "1.0.67" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3c69b077ad434294d3ce9f1f6143a2a4b89a8a2d54ef813d85003a4fd1137fd" + +[[package]] +name = "cfg-if" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "chrono" +version = "0.4.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "670ad68c9088c2a963aaa298cb369688cf3f9465ce5e2d4ca10e6e0098a1ce73" +dependencies = [ + "libc", + "num-integer", + "num-traits", + "serde", + "time 0.1.43", + "winapi", +] + +[[package]] +name = "cipher" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12f8e7987cbd042a63249497f41aed09f8e65add917ea6566effbc56578d6801" +dependencies = [ + "generic-array", +] + +[[package]] +name = "concurrent-queue" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30ed07550be01594c6026cff2a1d7fe9c8f683caa798e12b68694ac9e88286a3" +dependencies = [ + "cache-padded", +] + +[[package]] +name = "const_fn" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28b9d6de7f49e22cf97ad17fc4036ece69300032f45f78f30b4a4482cdc3f4a6" + +[[package]] +name = "constant_time_eq" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" + +[[package]] +name = "cookie" +version = "0.14.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "784ad0fbab4f3e9cef09f20e0aea6000ae08d2cb98ac4c0abc53df18803d702f" +dependencies = [ + "aes-gcm", + "base64 0.12.3", + "hkdf", + "hmac 0.10.1", + "percent-encoding", + "rand", + "sha2", + "time 0.2.25", + "version_check", +] + +[[package]] +name = "cpuid-bool" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8aebca1129a03dc6dc2b127edd729435bbc4a37e1d5f4d7513165089ceb02634" + +[[package]] +name = "cpuid-bool" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcb25d077389e53838a8158c8e99174c5a9d902dee4904320db714f3c653ffba" + +[[package]] +name = "crossbeam-queue" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "774ba60a54c213d409d5353bda12d49cd68d14e45036a285234c8d6f91f92570" +dependencies = [ + "cfg-if 0.1.10", + "crossbeam-utils 0.7.2", + "maybe-uninit", +] + +[[package]] +name = "crossbeam-utils" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3c7c73a2d1e9fc0886a08b93e98eb643461230d5f1925e4036204d5f2e261a8" +dependencies = [ + "autocfg", + "cfg-if 0.1.10", + "lazy_static", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9d99fa91428effe99c5c6d4634cdeba32b8cf784fc428a2a687f61a952c49" +dependencies = [ + "autocfg", + "cfg-if 1.0.0", + "lazy_static", +] + +[[package]] +name = "crypto-mac" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b584a330336237c1eecd3e94266efb216c56ed91225d634cb2991c5f3fd1aeab" +dependencies = [ + "generic-array", + "subtle", +] + +[[package]] +name = "crypto-mac" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4857fd85a0c34b3c3297875b747c1e02e06b6a0ea32dd892d8192b9ce0813ea6" +dependencies = [ + "generic-array", + "subtle", +] + +[[package]] +name = "ctor" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8f45d9ad417bcef4817d614a501ab55cdd96a6fdb24f49aab89a54acfd66b19" +dependencies = [ + "quote", + "syn", +] + +[[package]] +name = "ctr" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb4a30d54f7443bf3d6191dcd486aca19e67cb3c49fa7a06a319966346707e7f" +dependencies = [ + "cipher", +] + +[[package]] +name = "dashmap" +version = "4.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e77a43b28d0668df09411cb0bc9a8c2adc40f9a048afe863e05fd43251e8e39c" +dependencies = [ + "cfg-if 1.0.0", + "num_cpus", +] + +[[package]] +name = "data-encoding" +version = "2.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ee2393c4a91429dffb4bedf19f4d6abf27d8a732c8ce4980305d782e5426d57" + +[[package]] +name = "diesel" +version = "1.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e2de9deab977a153492a1468d1b1c0662c1cf39e5ea87d0c060ecd59ef18d8c" +dependencies = [ + "bitflags", + "byteorder", + "diesel_derives", + "pq-sys", + "r2d2", +] + +[[package]] +name = "diesel_derives" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45f5098f628d02a7a0f68ddba586fb61e80edec3bdc1be3b921f4ceec60858d3" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "digest" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" +dependencies = [ + "generic-array", +] + +[[package]] +name = "discard" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "212d0f5754cb6769937f4501cc0e67f4f4483c8d2c3e1e922ee9edbe4ab4c7c0" + +[[package]] +name = "event-listener" +version = "2.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7531096570974c3a9dcf9e4b8e1cede1ec26cf5046219fb3b9d897503b9be59" + +[[package]] +name = "fastrand" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca5faf057445ce5c9d4329e382b2ce7ca38550ef3b73a5348362d5f24e0c7fe3" +dependencies = [ + "instant", +] + +[[package]] +name = "femme" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2af1a24f391a5a94d756db5092c6576aad494b88a71a5a36b20c67b63e0df034" +dependencies = [ + "cfg-if 0.1.10", + "js-sys", + "log", + "serde", + "serde_derive", + "serde_json", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "form_urlencoded" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5fc25a87fa4fd2094bffb06925852034d90a17f0d1e05197d4956d3555752191" +dependencies = [ + "matches", + "percent-encoding", +] + +[[package]] +name = "funty" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fed34cd105917e91daa4da6b3728c47b068749d6a62c59811f06ed2ac71d9da7" + +[[package]] +name = "futures-channel" +version = "0.3.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c2dd2df839b57db9ab69c2c9d8f3e8c81984781937fe2807dc6dcf3b2ad2939" +dependencies = [ + "futures-core", +] + +[[package]] +name = "futures-core" +version = "0.3.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "15496a72fabf0e62bdc3df11a59a3787429221dd0710ba8ef163d6f7a9112c94" + +[[package]] +name = "futures-io" +version = "0.3.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d71c2c65c57704c32f5241c1223167c2c3294fd34ac020c807ddbe6db287ba59" + +[[package]] +name = "futures-lite" +version = "1.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4481d0cd0de1d204a4fa55e7d45f07b1d958abcb06714b3446438e2eff695fb" +dependencies = [ + "fastrand", + "futures-core", + "futures-io", + "memchr", + "parking", + "pin-project-lite 0.2.4", + "waker-fn", +] + +[[package]] +name = "futures-macro" +version = "0.3.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea405816a5139fb39af82c2beb921d52143f556038378d6db21183a5c37fbfb7" +dependencies = [ + "proc-macro-hack", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "futures-task" +version = "0.3.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa189ef211c15ee602667a6fcfe1c1fd9e07d42250d2156382820fba33c9df80" + +[[package]] +name = "futures-util" +version = "0.3.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1812c7ab8aedf8d6f2701a43e1243acdbcc2b36ab26e2ad421eb99ac963d96d1" +dependencies = [ + "futures-core", + "futures-macro", + "futures-task", + "pin-project-lite 0.2.4", + "pin-utils", + "proc-macro-hack", + "proc-macro-nested", + "slab", +] + +[[package]] +name = "generic-array" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "501466ecc8a30d1d3b7fc9229b122b2ce8ed6e9d9223f1138d4babb253e51817" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "getrandom" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" +dependencies = [ + "cfg-if 1.0.0", + "libc", + "wasi", +] + +[[package]] +name = "ghash" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97304e4cd182c3846f7575ced3890c53012ce534ad9114046b0a9e00bb30a375" +dependencies = [ + "opaque-debug", + "polyval", +] + +[[package]] +name = "gloo-timers" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47204a46aaff920a1ea58b11d03dec6f704287d27561724a4631e450654a891f" +dependencies = [ + "futures-channel", + "futures-core", + "js-sys", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "hermit-abi" +version = "0.1.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "322f4de77956e22ed0e5032c359a0f1273f1f7f0d79bfa3b8ffbc730d7fbcc5c" +dependencies = [ + "libc", +] + +[[package]] +name = "hkdf" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51ab2f639c231793c5f6114bdb9bbe50a7dbbfcd7c7c6bd8475dec2d991e964f" +dependencies = [ + "digest", + "hmac 0.10.1", +] + +[[package]] +name = "hmac" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "126888268dcc288495a26bf004b38c5fdbb31682f992c84ceb046a1f0fe38840" +dependencies = [ + "crypto-mac 0.8.0", + "digest", +] + +[[package]] +name = "hmac" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1441c6b1e930e2817404b5046f1f989899143a12bf92de603b69f4e0aee1e15" +dependencies = [ + "crypto-mac 0.10.0", + "digest", +] + +[[package]] +name = "http-client" +version = "6.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "034fc6371e1657295cd261c2f705941af300a8438ce41dedbdf74d674f52ad0f" +dependencies = [ + "async-trait", + "cfg-if 1.0.0", + "dashmap", + "http-types", + "log", +] + +[[package]] +name = "http-types" +version = "2.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32613ebb139d1d430ef5783676f84abfa06fc5f2b4b5a25220cdeeff7e16ef5c" +dependencies = [ + "anyhow", + "async-channel", + "async-std", + "base64 0.13.0", + "cookie", + "futures-lite", + "infer", + "pin-project-lite 0.2.4", + "rand", + "serde", + "serde_json", + "serde_qs", + "serde_urlencoded", + "url", +] + +[[package]] +name = "httparse" +version = "1.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "615caabe2c3160b313d52ccc905335f4ed5f10881dd63dc5699d47e90be85691" + +[[package]] +name = "humansize" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6cab2627acfc432780848602f3f558f7e9dd427352224b0d9324025796d2a5e" + +[[package]] +name = "idna" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89829a5d69c23d348314a7ac337fe39173b61149a9864deabd260983aed48c21" +dependencies = [ + "matches", + "unicode-bidi", + "unicode-normalization", +] + +[[package]] +name = "infer" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64e9829a50b42bb782c1df523f78d332fe371b10c661e78b7a3c34b0198e9fac" + +[[package]] +name = "instant" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61124eeebbd69b8190558df225adf7e4caafce0d743919e5d6b19652314ec5ec" +dependencies = [ + "cfg-if 1.0.0", +] + +[[package]] +name = "itoa" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd25036021b0de88a0aff6b850051563c6516d0bf53f8638938edbb9de732736" + +[[package]] +name = "js-sys" +version = "0.3.48" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc9f84f9b115ce7843d60706df1422a916680bfdfcbdb0447c5614ff9d7e4d78" +dependencies = [ + "wasm-bindgen", +] + +[[package]] +name = "kv-log-macro" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0de8b303297635ad57c9f5059fd9cee7a47f8e8daa09df0fcd07dd39fb22977f" +dependencies = [ + "log", +] + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "lexical-core" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21f866863575d0e1d654fbeeabdc927292fdf862873dc3c96c6f753357e13374" +dependencies = [ + "arrayvec", + "bitflags", + "cfg-if 1.0.0", + "ryu", + "static_assertions", +] + +[[package]] +name = "libc" +version = "0.2.86" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7282d924be3275cec7f6756ff4121987bc6481325397dde6ba3e7802b1a8b1c" + +[[package]] +name = "lock_api" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd96ffd135b2fd7b973ac026d28085defbe8983df057ced3eb4f2130b0831312" +dependencies = [ + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710" +dependencies = [ + "cfg-if 1.0.0", + "value-bag", +] + +[[package]] +name = "matches" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08" + +[[package]] +name = "maybe-uninit" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60302e4db3a61da70c0cb7991976248362f30319e88850c487b9b95bbf059e00" + +[[package]] +name = "memchr" +version = "2.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ee1c47aaa256ecabcaea351eae4a9b01ef39ed810004e298d2511ed284b1525" + +[[package]] +name = "nb-connect" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "670361df1bc2399ee1ff50406a0d422587dd3bb0da596e1978fe8e05dabddf4f" +dependencies = [ + "libc", + "socket2", +] + +[[package]] +name = "nom" +version = "6.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7413f999671bd4745a7b624bd370a569fb6bc574b23c83a3c5ed2e453f3d5e2" +dependencies = [ + "bitvec", + "funty", + "lexical-core", + "memchr", + "version_check", +] + +[[package]] +name = "num-integer" +version = "0.1.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db" +dependencies = [ + "autocfg", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290" +dependencies = [ + "autocfg", +] + +[[package]] +name = "num_cpus" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05499f3756671c15885fee9034446956fff3f243d6077b91e5767df161f766b3" +dependencies = [ + "hermit-abi", + "libc", +] + +[[package]] +name = "once_cell" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10acf907b94fc1b1a152d08ef97e7759650268cf986bf127f387e602b02c7e5a" + +[[package]] +name = "opaque-debug" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" + +[[package]] +name = "parking" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "427c3892f9e783d91cc128285287e70a59e206ca452770ece88a76f7a3eddd72" + +[[package]] +name = "parking_lot" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d7744ac029df22dca6284efe4e898991d28e3085c706c972bcd7da4a27a15eb" +dependencies = [ + "instant", + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa7a782938e745763fe6907fc6ba86946d72f49fe7e21de074e08128a99fb018" +dependencies = [ + "cfg-if 1.0.0", + "instant", + "libc", + "redox_syscall", + "smallvec", + "winapi", +] + +[[package]] +name = "percent-encoding" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" + +[[package]] +name = "pin-project" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96fa8ebb90271c4477f144354485b8068bd8f6b78b428b01ba892ca26caf0b63" +dependencies = [ + "pin-project-internal", +] + +[[package]] +name = "pin-project-internal" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "758669ae3558c6f74bd2a18b41f7ac0b5a195aea6639d6a9b5e5d1ad5ba24c0b" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "pin-project-lite" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c917123afa01924fc84bb20c4c03f004d9c38e5127e3c039bbf7f4b9c76a2f6b" + +[[package]] +name = "pin-project-lite" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439697af366c49a6d0a010c56a0d97685bc140ce0d377b13a2ea2aa42d64a827" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "polling" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2a7bc6b2a29e632e45451c941832803a18cce6781db04de8a04696cdca8bde4" +dependencies = [ + "cfg-if 0.1.10", + "libc", + "log", + "wepoll-sys", + "winapi", +] + +[[package]] +name = "polyval" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eebcc4aa140b9abd2bc40d9c3f7ccec842679cd79045ac3a7ac698c1a064b7cd" +dependencies = [ + "cpuid-bool 0.2.0", + "opaque-debug", + "universal-hash", +] + +[[package]] +name = "ppv-lite86" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857" + +[[package]] +name = "pq-sys" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ac25eee5a0582f45a67e837e350d784e7003bd29a5f460796772061ca49ffda" +dependencies = [ + "vcpkg", +] + +[[package]] +name = "proc-macro-hack" +version = "0.5.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5" + +[[package]] +name = "proc-macro-nested" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc881b2c22681370c6a780e47af9840ef841837bc98118431d4e1868bd0c1086" + +[[package]] +name = "proc-macro2" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e0704ee1a7e00d7bb417d0770ea303c1bccbabf0ef1667dae92b5967f5f8a71" +dependencies = [ + "unicode-xid", +] + +[[package]] +name = "quote" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "r2d2" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "545c5bc2b880973c9c10e4067418407a0ccaa3091781d1671d46eb35107cb26f" +dependencies = [ + "log", + "parking_lot", + "scheduled-thread-pool", +] + +[[package]] +name = "radium" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "941ba9d78d8e2f7ce474c015eea4d9c6d25b6a3327f9832ee29a4de27f91bbb8" + +[[package]] +name = "rand" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" +dependencies = [ + "getrandom", + "libc", + "rand_chacha", + "rand_core", + "rand_hc", + "rand_pcg", +] + +[[package]] +name = "rand_chacha" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rand_hc" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" +dependencies = [ + "rand_core", +] + +[[package]] +name = "rand_pcg" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16abd0c1b639e9eb4d7c50c0b8100b0d0f849be2349829c740fe8e6eb4816429" +dependencies = [ + "rand_core", +] + +[[package]] +name = "redox_syscall" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94341e4e44e24f6b591b59e47a8a027df12e008d73fd5672dbea9cc22f4507d9" +dependencies = [ + "bitflags", +] + +[[package]] +name = "route-recognizer" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56770675ebc04927ded3e60633437841581c285dc6236109ea25fbf3beb7b59e" + +[[package]] +name = "rustc_version" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" +dependencies = [ + "semver", +] + +[[package]] +name = "ryu" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e" + +[[package]] +name = "scheduled-thread-pool" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc6f74fd1204073fa02d5d5d68bec8021be4c38690b61264b2fdb48083d0e7d7" +dependencies = [ + "parking_lot", +] + +[[package]] +name = "scopeguard" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" + +[[package]] +name = "semver" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" +dependencies = [ + "semver-parser", +] + +[[package]] +name = "semver-parser" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" + +[[package]] +name = "serde" +version = "1.0.123" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92d5161132722baa40d802cc70b15262b98258453e85e5d1d365c757c73869ae" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.123" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9391c295d64fc0abb2c556bad848f33cb8296276b1ad2677d1ae1ace4f258f31" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.63" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43535db9747a4ba938c0ce0a98cc631a46ebf943c9e1d604e091df6007620bf6" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "serde_qs" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5af82de3c6549b001bec34961ff2d6a54339a87bab37ce901b693401f27de6cb" +dependencies = [ + "data-encoding", + "percent-encoding", + "serde", + "thiserror", +] + +[[package]] +name = "serde_urlencoded" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edfa57a7f8d9c1d260a549e7224100f6c43d43f9103e06dd8b4095a9b2b43ce9" +dependencies = [ + "form_urlencoded", + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "sha1" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2579985fda508104f7587689507983eadd6a6e84dd35d6d115361f530916fa0d" + +[[package]] +name = "sha2" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa827a14b29ab7f44778d14a88d3cb76e949c45083f7dbfa507d0cb699dc12de" +dependencies = [ + "block-buffer", + "cfg-if 1.0.0", + "cpuid-bool 0.1.2", + "digest", + "opaque-debug", +] + +[[package]] +name = "signal-hook" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a7f3f92a1da3d6b1d32245d0cbcbbab0cfc45996d8df619c42bccfa6d2bbb5f" +dependencies = [ + "libc", + "signal-hook-registry", +] + +[[package]] +name = "signal-hook-registry" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16f1d0fef1604ba8f7a073c7e701f213e056707210e9020af4528e0101ce11a6" +dependencies = [ + "libc", +] + +[[package]] +name = "simple-mutex" +version = "1.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38aabbeafa6f6dead8cebf246fe9fae1f9215c8d29b3a69f93bd62a9e4a3dcd6" +dependencies = [ + "event-listener", +] + +[[package]] +name = "slab" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8" + +[[package]] +name = "smallvec" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe0f37c9e8f3c5a4a66ad655a93c74daac4ad00c441533bf5c6e7990bb42604e" + +[[package]] +name = "socket2" +version = "0.3.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "122e570113d28d773067fab24266b66753f6ea915758651696b6e35e49f88d6e" +dependencies = [ + "cfg-if 1.0.0", + "libc", + "winapi", +] + +[[package]] +name = "stable_deref_trait" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" + +[[package]] +name = "standback" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2beb4d1860a61f571530b3f855a1b538d0200f7871c63331ecd6f17b1f014f8" +dependencies = [ + "version_check", +] + +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + +[[package]] +name = "stdweb" +version = "0.4.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d022496b16281348b52d0e30ae99e01a73d737b2f45d38fed4edf79f9325a1d5" +dependencies = [ + "discard", + "rustc_version", + "stdweb-derive", + "stdweb-internal-macros", + "stdweb-internal-runtime", + "wasm-bindgen", +] + +[[package]] +name = "stdweb-derive" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c87a60a40fccc84bef0652345bbbbbe20a605bf5d0ce81719fc476f5c03b50ef" +dependencies = [ + "proc-macro2", + "quote", + "serde", + "serde_derive", + "syn", +] + +[[package]] +name = "stdweb-internal-macros" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58fa5ff6ad0d98d1ffa8cb115892b6e69d67799f6763e162a1c9db421dc22e11" +dependencies = [ + "base-x", + "proc-macro2", + "quote", + "serde", + "serde_derive", + "serde_json", + "sha1", + "syn", +] + +[[package]] +name = "stdweb-internal-runtime" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "213701ba3370744dcd1a12960caa4843b3d68b4d1c0a5d575e0d65b2ee9d16c0" + +[[package]] +name = "subtle" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e81da0851ada1f3e9d4312c704aa4f8806f0f9d69faaf8df2f3464b4a9437c2" + +[[package]] +name = "sval" +version = "1.0.0-alpha.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45f6ee7c7b87caf59549e9fe45d6a69c75c8019e79e212a835c5da0e92f0ba08" + +[[package]] +name = "syn" +version = "1.0.60" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c700597eca8a5a762beb35753ef6b94df201c81cca676604f547495a0d7f0081" +dependencies = [ + "proc-macro2", + "quote", + "unicode-xid", +] + +[[package]] +name = "tap" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" + +[[package]] +name = "thiserror" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0f4a65597094d4483ddaed134f409b2cb7c1beccf25201a9f73c719254fa98e" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7765189610d8241a44529806d6fd1f2e0a08734313a35d5b3a556f92b381f3c0" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tide" +version = "0.1.0" +dependencies = [ + "askama", + "async-std", + "async-trait", + "diesel", + "http-types", + "rand", + "serde", + "tide 0.16.0", +] + +[[package]] +name = "tide" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c459573f0dd2cc734b539047f57489ea875af8ee950860ded20cf93a79a1dee0" +dependencies = [ + "async-h1", + "async-session", + "async-sse", + "async-std", + "async-trait", + "femme", + "futures-util", + "http-client", + "http-types", + "kv-log-macro", + "log", + "pin-project-lite 0.2.4", + "route-recognizer", + "serde", + "serde_json", +] + +[[package]] +name = "time" +version = "0.1.43" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca8a50ef2360fbd1eeb0ecd46795a87a19024eb4b53c5dc916ca1fd95fe62438" +dependencies = [ + "libc", + "winapi", +] + +[[package]] +name = "time" +version = "0.2.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1195b046942c221454c2539395f85413b33383a067449d78aab2b7b052a142f7" +dependencies = [ + "const_fn", + "libc", + "standback", + "stdweb", + "time-macros", + "version_check", + "winapi", +] + +[[package]] +name = "time-macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "957e9c6e26f12cb6d0dd7fc776bb67a706312e7299aed74c8dd5b17ebb27e2f1" +dependencies = [ + "proc-macro-hack", + "time-macros-impl", +] + +[[package]] +name = "time-macros-impl" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5c3be1edfad6027c69f5491cf4cb310d1a71ecd6af742788c6ff8bced86b8fa" +dependencies = [ + "proc-macro-hack", + "proc-macro2", + "quote", + "standback", + "syn", +] + +[[package]] +name = "tinyvec" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "317cca572a0e89c3ce0ca1f1bdc9369547fe318a683418e42ac8f59d14701023" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" + +[[package]] +name = "toml" +version = "0.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a31142970826733df8241ef35dc040ef98c679ab14d7c3e54d827099b3acecaa" +dependencies = [ + "serde", +] + +[[package]] +name = "typenum" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "373c8a200f9e67a0c95e62a4f52fbf80c23b4381c05a17845531982fa99e6b33" + +[[package]] +name = "unicode-bidi" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5" +dependencies = [ + "matches", +] + +[[package]] +name = "unicode-normalization" +version = "0.1.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07fbfce1c8a97d547e8b5334978438d9d6ec8c20e38f56d4a4374d181493eaef" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "unicode-xid" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564" + +[[package]] +name = "universal-hash" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8326b2c654932e3e4f9196e69d08fdf7cfd718e1dc6f66b347e6024a0c961402" +dependencies = [ + "generic-array", + "subtle", +] + +[[package]] +name = "url" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ccd964113622c8e9322cfac19eb1004a07e636c545f325da085d5cdde6f1f8b" +dependencies = [ + "form_urlencoded", + "idna", + "matches", + "percent-encoding", + "serde", +] + +[[package]] +name = "value-bag" +version = "1.0.0-alpha.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b676010e055c99033117c2343b33a40a30b91fecd6c49055ac9cd2d6c305ab1" +dependencies = [ + "ctor", + "sval", +] + +[[package]] +name = "vcpkg" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b00bca6106a5e23f3eee943593759b7fcddb00554332e856d990c893966879fb" + +[[package]] +name = "vec-arena" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eafc1b9b2dfc6f5529177b62cf806484db55b32dc7c9658a118e11bbeb33061d" + +[[package]] +name = "version_check" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5a972e5669d67ba988ce3dc826706fb0a8b01471c088cb0b6110b805cc36aed" + +[[package]] +name = "waker-fn" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d5b2c62b4012a3e1eca5a7e077d13b3bf498c4073e33ccd58626607748ceeca" + +[[package]] +name = "wasi" +version = "0.9.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" + +[[package]] +name = "wasm-bindgen" +version = "0.2.71" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ee1280240b7c461d6a0071313e08f34a60b0365f14260362e5a2b17d1d31aa7" +dependencies = [ + "cfg-if 1.0.0", + "serde", + "serde_json", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.71" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b7d8b6942b8bb3a9b0e73fc79b98095a27de6fa247615e59d096754a3bc2aa8" +dependencies = [ + "bumpalo", + "lazy_static", + "log", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e67a5806118af01f0d9045915676b22aaebecf4178ae7021bc171dab0b897ab" +dependencies = [ + "cfg-if 1.0.0", + "js-sys", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.71" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5ac38da8ef716661f0f36c0d8320b89028efe10c7c0afde65baffb496ce0d3b" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.71" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc053ec74d454df287b9374ee8abb36ffd5acb95ba87da3ba5b7d3fe20eb401e" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.71" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d6f8ec44822dd71f5f221a5847fb34acd9060535c1211b70a05844c0f6383b1" + +[[package]] +name = "web-sys" +version = "0.3.48" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec600b26223b2948cedfde2a0aa6756dcf1fef616f43d7b3097aaf53a6c4d92b" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "wepoll-sys" +version = "3.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fcb14dea929042224824779fbc82d9fab8d2e6d3cbc0ac404de8edf489e77ff" +dependencies = [ + "cc", +] + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "wyz" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85e60b0d1b5f99db2556934e21937020776a5d31520bf169e851ac44e6420214" diff --git a/frameworks/Rust/tide/Cargo.toml b/frameworks/Rust/tide/Cargo.toml new file mode 100644 index 00000000000..269c10835e5 --- /dev/null +++ b/frameworks/Rust/tide/Cargo.toml @@ -0,0 +1,20 @@ +[package] +name = "tide" +version = "0.1.0" +authors = ["Tom Milligan "] +edition = "2018" + +[dependencies] +askama = "0.10.5" +async-std = { version = "1.9.0", features = ["attributes"] } +async-trait = "0.1.42" +diesel = { version = "1.4.5", features = ["postgres", "r2d2"] } +http-types = "2.10.0" +rand = { version = "0.7", features = ["small_rng"] } +serde = { version = "1.0.123", features = ["derive"] } +tide = "0.16.0" + +[profile.release] +codegen-units = 1 +opt-level = 3 +lto = true diff --git a/frameworks/Rust/tide/README.md b/frameworks/Rust/tide/README.md new file mode 100755 index 00000000000..6c16654e152 --- /dev/null +++ b/frameworks/Rust/tide/README.md @@ -0,0 +1,27 @@ +# tide + +[Tide](https://github.com/http-rs/tide) is a minimal and pragmatic Rust web application framework built for rapid development. It comes with a robust set of features that make building async web applications and APIs easier and more fun. + +## Benchmark Implementation + +This implementation is largely based on the `actix` and `warp` implementation. Thanks to everyone who worked on them. + +### Database + +PostgreSQL, ORM using [diesel](http://diesel.rs), the de facto standard for Rust ORM. + +### Routes + +| Benchmark | Name | URL | +| --------- | ----------------------------- | ------------------------------------ | +| Test 1 | JSON Encoding | http://localhost:8080/json | +| Test 2 | Single Row Query | http://localhost:8080/db | +| Test 3 | Multi Row Query | http://localhost:8080/queries/:count | +| Test 4 | Fortunes (Template rendering) | http://localhost:8080/fortune | +| Test 5 | Update Query | http://localhost:8080/updates/:count | +| Test 6 | Plaintext | http://localhost:8080/plaintext | + +### Implementation + +Routing is defined in [`main.rs`](src/main.rs). +Top level request handling is defined in [`handlers.rs`](src/handlers.rs). diff --git a/frameworks/Rust/tide/benchmark_config.json b/frameworks/Rust/tide/benchmark_config.json new file mode 100755 index 00000000000..61aa0e2c5d4 --- /dev/null +++ b/frameworks/Rust/tide/benchmark_config.json @@ -0,0 +1,30 @@ +{ + "framework": "tide", + "tests": [ + { + "default": { + "json_url": "/json", + "plaintext_url": "/plaintext", + "db_url": "/db", + "query_url": "/queries/", + "fortune_url": "/fortunes", + "update_url": "/updates/", + "port": 8080, + "approach": "Realistic", + "classification": "Micro", + "database": "Postgres", + "framework": "tide", + "language": "Rust", + "flavor": "None", + "orm": "Full", + "platform": "Rust", + "webserver": "tide", + "os": "Linux", + "database_os": "Linux", + "display_name": "tide", + "notes": "", + "versus": "None" + } + } + ] +} diff --git a/frameworks/Rust/tide/config.toml b/frameworks/Rust/tide/config.toml new file mode 100644 index 00000000000..6a1e0abaf37 --- /dev/null +++ b/frameworks/Rust/tide/config.toml @@ -0,0 +1,19 @@ +[framework] +name = "tide" + +[main] +urls.plaintext = "/plaintext" +urls.json = "/json" +urls.db = "/db" +urls.query = "/queries/" +urls.fortune = "/fortunes" +urls.update = "/updates/" +approach = "Realistic" +classification = "Micro" +database = "Postgres" +database_os = "Linux" +os = "Linux" +orm = "Full" +platform = "Rust" +webserver = "tide" +versus = "None" diff --git a/frameworks/Rust/tide/src/db.rs b/frameworks/Rust/tide/src/db.rs new file mode 100644 index 00000000000..b0894e81c47 --- /dev/null +++ b/frameworks/Rust/tide/src/db.rs @@ -0,0 +1,25 @@ +//! Database related utilities. + +use diesel::{pg::PgConnection, r2d2}; +use std::time::Duration; + +const DATABASE_URL: &str = "postgres://benchmarkdbuser:benchmarkdbpass@tfb-database/hello_world"; + +/// A shared pool of DB connections used across the server. +pub type Pool = r2d2::Pool>; + +/// A single connection, checked out from the shared pool. +pub type Connection = r2d2::PooledConnection>; + +/// Setup the shared database connection pool, configured for benchmarking. +pub fn connect() -> Pool { + let manager = r2d2::ConnectionManager::new(DATABASE_URL); + r2d2::Builder::new() + // Double maxiumum benchmark concurrency + .max_size(1024) + // Minimum benchmark concurrency + .min_idle(Some(16)) + .connection_timeout(Duration::from_secs(5)) + .build(manager) + .expect("building r2d2 connection pool") +} diff --git a/frameworks/Rust/tide/src/handlers.rs b/frameworks/Rust/tide/src/handlers.rs new file mode 100644 index 00000000000..c612539899f --- /dev/null +++ b/frameworks/Rust/tide/src/handlers.rs @@ -0,0 +1,154 @@ +//! Functions that handle each request, returning a valid response. + +use crate::{ + db::Pool, + models::{Fortune, Message, World}, + rand::random_10k, +}; +use askama::Template; +use diesel::prelude::*; +use tide::{Body, Error, Request, Response, Result}; + +/// Return a static plaintext body. +pub async fn plaintext(_request: Request) -> Result { + Ok(Response::builder(200).body("Hello, World!").build()) +} + +/// Return a static JSON body. +pub async fn json(_request: Request) -> Result { + Ok(Response::builder(200) + .body(Body::from_json(&Message { + message: "Hello, World!", + })?) + .build()) +} + +/// Load a single random `World` from the database. +fn load_world(connection: &crate::db::Connection) -> Result { + use crate::schema::world::dsl::{id, world}; + + Ok(world + .filter(id.eq(random_10k())) + .load::(connection) + .map_err(|error| Error::new(500, error))? + .pop() + .expect("one item in world query result")) +} + +/// Return a single random `World` as JSON. +pub async fn db(request: Request) -> Result { + let connection = request.state().get()?; + let loaded_world = load_world(&connection)?; + + Ok(Response::builder(200) + .body(Body::from_json(&loaded_world)?) + .build()) +} + +/// Get the count parameter from the request route, normalizing invalid values. +/// +/// Return an integer in the range 1 - 500. +fn get_count_param(request: &Request) -> usize { + const _COUNT_MIN: usize = 1; + const _COUNT_MAX: usize = 500; + + let mut count = request + .param("count") + .unwrap_or("1") + .parse() + .unwrap_or(_COUNT_MIN); + if count > _COUNT_MAX { + count = _COUNT_MAX; + } else if count < _COUNT_MIN { + count = _COUNT_MIN; + } + count +} + +/// Return a variable number of random `World`s as a JSON list. +pub async fn queries(request: Request) -> Result { + let count = get_count_param(&request); + + let mut loaded_worlds = Vec::with_capacity(count); + let connection = request.state().get()?; + for _index in 0..count { + loaded_worlds.push(load_world(&connection)?); + } + + Ok(Response::builder(200) + .body(Body::from_json(&loaded_worlds)?) + .build()) +} + +/// Template to render `Fortune`s as a HTML list. +#[derive(Template)] +#[template(path = "fortune.html")] +struct FortuneTemplate<'a> { + items: &'a Vec, +} + +/// Return all `Fortune`s rendered as HTML. +pub async fn fortunes(request: Request) -> Result { + use crate::schema::fortune::dsl::fortune; + + let connection = request.state().get()?; + let mut items = fortune + .load::(&connection) + .map_err(|error| Error::new(500, error))?; + items.push(Fortune { + id: 0, + message: "Additional fortune added at request time.".to_string(), + }); + items.sort_by(|item, next| item.message.cmp(&next.message)); + + let template = FortuneTemplate { items: &items }; + let html = template.render().expect("template to render"); + + Ok(Response::builder(200) + .body(Body::from_string(html)) + .content_type(http_types::mime::HTML) + .build()) +} + +/// Update a variable number of random `World`s, returning them as a JSON list. +pub async fn updates(request: Request) -> Result { + let count = get_count_param(&request); + let connection = request.state().get()?; + let mut loaded_worlds = Vec::with_capacity(count); + for _index in 0..count { + let mut loaded_world = load_world(&connection)?; + loaded_world.randomnumber = random_10k(); + loaded_worlds.push(loaded_world); + } + + // This line is required to pass test verification otherwise we get: + // + // ``` + // FAIL for http://tfb-server:8080/updates/20 + // Only 20470 executed queries in the database out of roughly 20480 expected. + // PASS for http://tfb-server:8080/updates/20 + // Rows read: 10128/10240 + // FAIL for http://tfb-server:8080/updates/20 + // Only 10118 rows updated in the database out of roughly 10240 expected. + // ``` + // + // I don't know why this is the case, but I copied it from the actix + // implementation and here it shall stay. + loaded_worlds.sort_by_key(|loaded_world| loaded_world.id); + + let _ = connection.transaction::<(), Error, _>(|| { + for loaded_world in &loaded_worlds { + use crate::schema::world::dsl::{id, randomnumber, world}; + diesel::update(world) + .filter(id.eq(loaded_world.id)) + .set(randomnumber.eq(loaded_world.randomnumber)) + .execute(&connection) + .map_err(|error| Error::new(500, error))?; + } + Ok(()) + }); + + Ok(Response::builder(200) + .body(Body::from_json(&loaded_worlds)?) + .build()) +} diff --git a/frameworks/Rust/tide/src/main.rs b/frameworks/Rust/tide/src/main.rs new file mode 100644 index 00000000000..8a7db9a42e9 --- /dev/null +++ b/frameworks/Rust/tide/src/main.rs @@ -0,0 +1,58 @@ +#[macro_use] +extern crate diesel; + +mod db; +mod handlers; +mod middleware; +mod models; +mod rand; +mod schema; + +use db::Pool; + +/// Configure server routing to handlers. +fn configure(app: &mut tide::Server) { + // 1. JSON Serialization + app.at("/json").get(handlers::json); + + // 2. Single Database Query + app.at("/db").get(handlers::db); + + // 3. Multiple Database Queries + // + // AFAIK tide doesn't support optional route paramters. + // + // In the cases where the count parameter isn't given, we still want + // to use the same handler. + // + // Using a query parameter might be more idiomatic. + app.at("/queries/").get(handlers::queries); + app.at("/queries/:count").get(handlers::queries); + + // 4. Fortunes + app.at("/fortunes").get(handlers::fortunes); + + // 5. Database Updates + app.at("/updates/").get(handlers::updates); + app.at("/updates/:count").get(handlers::updates); + + // 6. Plaintext + app.at("/plaintext").get(handlers::plaintext); +} + +#[async_std::main] +async fn main() -> Result<(), std::io::Error> { + let pool = db::connect(); + let mut app = tide::with_state(pool); + configure(&mut app); + + // The benchmarks require the 'server' header is set on every response + app.with(middleware::ServerHeader); + + // Uncomment these lines to enable debug logging + // tide::log::start(); + // app.with(tide::log::LogMiddleware::new()); + + app.listen("0.0.0.0:8080").await?; + Ok(()) +} diff --git a/frameworks/Rust/tide/src/middleware.rs b/frameworks/Rust/tide/src/middleware.rs new file mode 100644 index 00000000000..02c7ee81568 --- /dev/null +++ b/frameworks/Rust/tide/src/middleware.rs @@ -0,0 +1,16 @@ +//! Middleware that applies to mane requests at the HTTP level. + +use tide::{Middleware, Next, Request, Result}; + +/// Middleware to add the `server` header to each response. +#[derive(Debug, Default, Clone)] +pub struct ServerHeader; + +#[async_trait::async_trait] +impl Middleware for ServerHeader { + async fn handle(&self, request: Request, next: Next<'_, State>) -> Result { + let mut response = next.run(request).await; + response.insert_header("server", "tide"); + Ok(response) + } +} diff --git a/frameworks/Rust/tide/src/models.rs b/frameworks/Rust/tide/src/models.rs new file mode 100644 index 00000000000..5a6659e0340 --- /dev/null +++ b/frameworks/Rust/tide/src/models.rs @@ -0,0 +1,23 @@ +//! Structs with support for database/JSON serde. + +use diesel::Queryable; +use serde::{Deserialize, Serialize}; + +#[derive(Serialize, Deserialize)] +pub struct Message { + pub message: &'static str, +} + +#[allow(non_snake_case)] +#[derive(Serialize, Queryable, Debug)] +pub struct World { + pub id: i32, + pub randomnumber: i32, +} + +#[allow(non_snake_case)] +#[derive(Serialize, Queryable, Debug)] +pub struct Fortune { + pub id: i32, + pub message: String, +} diff --git a/frameworks/Rust/tide/src/rand.rs b/frameworks/Rust/tide/src/rand.rs new file mode 100644 index 00000000000..d7eea5d9b9b --- /dev/null +++ b/frameworks/Rust/tide/src/rand.rs @@ -0,0 +1,18 @@ +//! Utilities for random behaviour required by the benchmarks. + +use rand::{rngs::SmallRng, Rng, SeedableRng}; +use std::cell::RefCell; + +thread_local!( + static RNG: RefCell = RefCell::new(SmallRng::from_entropy()); +); + +/// Use a thread local rng with the given closure. +fn with_rng(f: impl FnOnce(&mut SmallRng) -> T) -> T { + RNG.with(|rng| f(&mut rng.borrow_mut())) +} + +/// Return a random number from 1 - 10,000 inclusive. +pub fn random_10k() -> i32 { + with_rng(|rng| rng.gen_range(1, 10_001)) +} diff --git a/frameworks/Rust/tide/src/schema.rs b/frameworks/Rust/tide/src/schema.rs new file mode 100644 index 00000000000..fba72376e77 --- /dev/null +++ b/frameworks/Rust/tide/src/schema.rs @@ -0,0 +1,15 @@ +//! Database schema as defined by the benchmark fixtures. + +table! { + world (id) { + id -> Integer, + randomnumber -> Integer, + } +} + +table! { + fortune (id) { + id -> Integer, + message -> Text, + } +} diff --git a/frameworks/Rust/tide/templates/fortune.html b/frameworks/Rust/tide/templates/fortune.html new file mode 100644 index 00000000000..7c448b9d999 --- /dev/null +++ b/frameworks/Rust/tide/templates/fortune.html @@ -0,0 +1,12 @@ + + + Fortunes + + + + {% for item in items %} + + {% endfor %} +
idmessage
{{item.id}}{{item.message}}
+ + diff --git a/frameworks/Rust/tide/tide.dockerfile b/frameworks/Rust/tide/tide.dockerfile new file mode 100644 index 00000000000..151f1a840c1 --- /dev/null +++ b/frameworks/Rust/tide/tide.dockerfile @@ -0,0 +1,12 @@ +FROM rust:1.50 + +WORKDIR /tide +COPY src src +COPY templates templates +COPY Cargo.toml Cargo.toml + +RUN RUSTFLAGS="-C target-cpu=native" cargo build --release + +EXPOSE 8080 + +CMD ./target/release/tide diff --git a/frameworks/Rust/warp-rust/Cargo.toml b/frameworks/Rust/warp-rust/Cargo.toml index f9f4cf7ae10..29bda01013c 100644 --- a/frameworks/Rust/warp-rust/Cargo.toml +++ b/frameworks/Rust/warp-rust/Cargo.toml @@ -11,7 +11,7 @@ serde = { version = "1.0.120", features = ["derive"] } sqlx = { version = "0.5.1", features = ["runtime-tokio-rustls", "postgres"] } tokio = { version = "1.0.2", features = ["macros", "rt-multi-thread"] } warp = "0.3.0" -yarte = "0.14.1" +yarte = "0.15.3" [profile.release] codegen-units = 1 diff --git a/frameworks/Swift/hummingbird/README.md b/frameworks/Swift/hummingbird/README.md new file mode 100755 index 00000000000..8dcc4045199 --- /dev/null +++ b/frameworks/Swift/hummingbird/README.md @@ -0,0 +1,22 @@ +# Hummingbird Benchmarking Test + +Hummingbird is a lightweight, flexible HTTP server framework written in Swift. It is a micro framework so there are no benchmarks for database access + +### Test Type Implementation Source Code + +* [JSON](src/Sources/server/main.swift) +* [PLAINTEXT](src/Sources/server/main.swift) + +## Important Libraries +This version of Hummingbird requires +* [Swift 5.3](https://swift.org) +* [SwiftNIO 2.x](https://github.com/apple/swift-nio/) + +## Test URLs +### JSON + +http://localhost:8080/json + +### PLAINTEXT + +http://localhost:8080/plaintext diff --git a/frameworks/Swift/hummingbird/benchmark_config.json b/frameworks/Swift/hummingbird/benchmark_config.json new file mode 100755 index 00000000000..ed4b81482c4 --- /dev/null +++ b/frameworks/Swift/hummingbird/benchmark_config.json @@ -0,0 +1,26 @@ +{ + "framework": "hummingbird", + "tests": [ + { + "default": { + "json_url": "/json", + "plaintext_url": "/plaintext", + "port": 8080, + "approach": "Realistic", + "classification": "Micro", + "database": "None", + "framework": "Hummingbird", + "language": "Swift", + "flavor": "None", + "orm": "None", + "platform": "None", + "webserver": "None", + "os": "Linux", + "database_os": "Linux", + "display_name": "Hummingbird", + "notes": "", + "versus": "None" + } + } + ] +} diff --git a/frameworks/Swift/hummingbird/hummingbird.dockerfile b/frameworks/Swift/hummingbird/hummingbird.dockerfile new file mode 100644 index 00000000000..a4d76350078 --- /dev/null +++ b/frameworks/Swift/hummingbird/hummingbird.dockerfile @@ -0,0 +1,29 @@ +# ================================ +# Build image +# ================================ +FROM swift:5.3 as build +WORKDIR /build + +# Copy entire repo into container +COPY ./src . + +# Compile with optimizations +RUN swift build \ + --enable-test-discovery \ + -c release + +# ================================ +# Run image +# ================================ +FROM swift:5.3-slim +WORKDIR /run + +# Copy build artifacts +COPY --from=build /build/.build/release /run + +ENV SERVER_PORT=8080 +ENV SERVER_HOSTNAME=0.0.0.0 + +EXPOSE 8080 + +CMD ["./server"] diff --git a/frameworks/Swift/hummingbird/src/Package.swift b/frameworks/Swift/hummingbird/src/Package.swift new file mode 100644 index 00000000000..299707bdd60 --- /dev/null +++ b/frameworks/Swift/hummingbird/src/Package.swift @@ -0,0 +1,28 @@ +// swift-tools-version:5.3 +// The swift-tools-version declares the minimum version of Swift required to build this package. + +import PackageDescription + +let package = Package( + name: "server", + products: [ + .executable(name: "server", targets: ["server"]) + ], + dependencies: [ + .package(url: "https://github.com/hummingbird-project/hummingbird.git", .upToNextMinor(from: "0.6.0")), + ], + targets: [ + .target(name: "server", + dependencies: [ + .product(name: "Hummingbird", package: "hummingbird"), + .product(name: "HummingbirdFoundation", package: "hummingbird"), + ], + swiftSettings: [ + // Enable better optimizations when building in Release configuration. Despite the use of + // the `.unsafeFlags` construct required by SwiftPM, this flag is recommended for Release + // builds. See for details. + .unsafeFlags(["-cross-module-optimization"], .when(configuration: .release)) + ] + ), + ] +) diff --git a/frameworks/Swift/hummingbird/src/Sources/server/main.swift b/frameworks/Swift/hummingbird/src/Sources/server/main.swift new file mode 100644 index 00000000000..413d86f5b84 --- /dev/null +++ b/frameworks/Swift/hummingbird/src/Sources/server/main.swift @@ -0,0 +1,33 @@ +import Hummingbird +import HummingbirdFoundation + +struct Object: HBResponseEncodable { + let message: String +} + +func runApp() { + let env = HBEnvironment() + let serverHostName = env.get("SERVER_HOSTNAME") ?? "127.0.0.1" + let serverPort = env.get("SERVER_PORT", as: Int.self) ?? 8080 + + let configuration = HBApplication.Configuration( + address: .hostname(serverHostName, port: serverPort), + serverName: "Hummingbird" + ) + let app = HBApplication(configuration: configuration) + app.encoder = JSONEncoder() + app.middleware.add(HBDateResponseMiddleware(application: app)) + + app.router.get("plaintext") { req in + "Hello, world!" + } + + app.router.get("json") { req in + Object(message: "Hello, world!") + } + + app.start() + app.wait() +} + +runApp() diff --git a/frameworks/Swift/swift-nio/app/Sources/main.swift b/frameworks/Swift/swift-nio/app/Sources/main.swift index 42bcd4ef223..ce51a8a7b0c 100644 --- a/frameworks/Swift/swift-nio/app/Sources/main.swift +++ b/frameworks/Swift/swift-nio/app/Sources/main.swift @@ -41,9 +41,9 @@ private final class HTTPHandler: ChannelInboundHandler { switch self.unwrapInboundIn(data) { case .head(let request): switch request.uri { - case "/p": + case "/plaintext": self.processPlaintext(context: context) - case "/j": + case "/json": do { try self.processJSON(context: context) } catch { diff --git a/frameworks/Swift/swift-nio/benchmark_config.json b/frameworks/Swift/swift-nio/benchmark_config.json index 4f195998b3b..69c74d67124 100644 --- a/frameworks/Swift/swift-nio/benchmark_config.json +++ b/frameworks/Swift/swift-nio/benchmark_config.json @@ -2,8 +2,8 @@ "framework": "swift-nio", "tests": [{ "default": { - "json_url": "/j", - "plaintext_url": "/p", + "json_url": "/json", + "plaintext_url": "/plaintext", "port": 8080, "approach": "Realistic", "classification": "Platform", diff --git a/frameworks/Swift/swift-nio/swift-nio.dockerfile b/frameworks/Swift/swift-nio/swift-nio.dockerfile index 18326e9ef45..a3921e118fb 100644 --- a/frameworks/Swift/swift-nio/swift-nio.dockerfile +++ b/frameworks/Swift/swift-nio/swift-nio.dockerfile @@ -1,7 +1,7 @@ # ================================ # Build image # ================================ -FROM swift:5.1 as build +FROM swift:5.3 as build WORKDIR /build # Copy entire repo into container @@ -15,7 +15,7 @@ RUN swift build \ # ================================ # Run image # ================================ -FROM ubuntu:18.04 +FROM swift:5.3-slim WORKDIR /run # Install Swift dependencies diff --git a/frameworks/TypeScript/deno/config.toml b/frameworks/TypeScript/deno/config.toml index c2685915eb4..a2382d14449 100644 --- a/frameworks/TypeScript/deno/config.toml +++ b/frameworks/TypeScript/deno/config.toml @@ -4,10 +4,16 @@ name = "deno" [main] urls.plaintext = "/plaintext" urls.json = "/json" +urls.db = "/db" +urls.query = "/query?queries=" +urls.update = "/update?queries=" +urls.fortune = "/fortunes" approach = "Realistic" classification = "Platform" database_os = "Linux" +database = "MongoDB" os = "Linux" +orm = "Raw" platform = "deno" webserver = "None" versus = "nodejs" diff --git a/frameworks/TypeScript/deno/deno.dockerfile b/frameworks/TypeScript/deno/deno.dockerfile index e4ab15b8f66..44f6b8e6fd1 100644 --- a/frameworks/TypeScript/deno/deno.dockerfile +++ b/frameworks/TypeScript/deno/deno.dockerfile @@ -1,10 +1,11 @@ -FROM hayd/alpine-deno:1.0.0 +FROM hayd/alpine-deno:1.8.1 EXPOSE 8080 WORKDIR /app USER deno +ENV DATABASE mongodb COPY ./src . diff --git a/frameworks/TypeScript/deno/src/_handlers/json.ts b/frameworks/TypeScript/deno/src/_handlers/json.ts new file mode 100644 index 00000000000..b48f799499e --- /dev/null +++ b/frameworks/TypeScript/deno/src/_handlers/json.ts @@ -0,0 +1,16 @@ +import { ServerRequest, SERVER, dyn_date, MIME_JSON } from "../depends.ts"; + +export const headers = new Headers([ + ["server", SERVER], + ["content-type", MIME_JSON], +]); + +export default async (req: ServerRequest): Promise => { + const HELLO_OBJ = { message: "Hello, World!" }; + headers.set("date", dyn_date()); + req.respond({ + headers, + body: JSON.stringify(HELLO_OBJ), + }); + return; +}; diff --git a/frameworks/TypeScript/deno/src/_handlers/mongodb-raw/_db_helpers.ts b/frameworks/TypeScript/deno/src/_handlers/mongodb-raw/_db_helpers.ts new file mode 100644 index 00000000000..ac132d8ec1a --- /dev/null +++ b/frameworks/TypeScript/deno/src/_handlers/mongodb-raw/_db_helpers.ts @@ -0,0 +1,87 @@ +import { MongoClient } from "../../depends.ts"; + +const mongoUrl = "mongodb://tfb-database:27017"; +const dbName = "hello_world"; + +export const client: MongoClient = new MongoClient(); +await client.connect(mongoUrl); +export let World = client.database(dbName).collection("world"); +export let Fortune = client.database(dbName).collection("fortune"); + +export const randomNumber = (): number => Math.floor(Math.random() * 10000) + 1; + +export const fillArray = async (v: T, l: number) => { + let o = []; + for (let i = 0; i < l; i += 1) o.push(v); + return o; +}; + +export interface FortuneData { + id: number; + message: string; + _id?: unknown; +} +export const _fortunes_head = [ + "", + "", + "Fortunes", + "", + "", + "", + "", + "", + "", +].join(""); +export const _fortunes_end = ["
idmessage
", "", ""].join(""); +export const _fortunes_com = ["", "", "", ""]; +export const generateFortunes = (input: FortuneData[]): string => { + let f = input + .map( + (v) => + _fortunes_com[0] + + +_fortunes_com[2] + + v.id + + _fortunes_com[3] + + _fortunes_com[2] + + v.message + + _fortunes_com[3] + + _fortunes_com[1] + ) + .join(""); + + return _fortunes_head + f + _fortunes_end; +}; + +export const randomWorld = async () => { + let world = (await World.findOne({ + id: randomNumber(), + })) as FortuneData; + world._id = undefined; + return world; +}; + +export const getAllFortunes = async () => { + return await Fortune.find().toArray(); +}; + +export const updateQuery = async () => { + const one = (await World.findOne({ + id: randomNumber(), + })) as any; + one.randomNumber = randomNumber(); + await World.updateOne( + { + id: one.id, + }, + one + ); + return { + id: one.id, + randomNumber: one.randomNumber, + }; +}; + +export const additionalFortune = { + id: 0, + message: "Additional fortune added at request time.", +}; diff --git a/frameworks/TypeScript/deno/src/_handlers/mongodb-raw/fortunes.ts b/frameworks/TypeScript/deno/src/_handlers/mongodb-raw/fortunes.ts new file mode 100644 index 00000000000..22839297688 --- /dev/null +++ b/frameworks/TypeScript/deno/src/_handlers/mongodb-raw/fortunes.ts @@ -0,0 +1,23 @@ +import { ServerRequest, SERVER, dyn_date, MIME_HTML } from "../../depends.ts"; +import { + getAllFortunes, + additionalFortune, + generateFortunes, + FortuneData, +} from "./_db_helpers.ts"; + +export const headers = new Headers([ + ["server", SERVER], + ["content-type", MIME_HTML], +]); + +export default async (req: ServerRequest): Promise => { + let fortunes = await getAllFortunes(); + fortunes.push(additionalFortune); + fortunes.sort((a: any, b: any) => a.message.localeCompare(b.message)); + headers.set("date", dyn_date()); + req.respond({ + headers, + body: generateFortunes(fortunes as FortuneData[]), + }); +}; diff --git a/frameworks/TypeScript/deno/src/_handlers/mongodb-raw/multiple-queries.ts b/frameworks/TypeScript/deno/src/_handlers/mongodb-raw/multiple-queries.ts new file mode 100644 index 00000000000..30537e601e6 --- /dev/null +++ b/frameworks/TypeScript/deno/src/_handlers/mongodb-raw/multiple-queries.ts @@ -0,0 +1,18 @@ +import { ServerRequest, SERVER, dyn_date, MIME_JSON } from "../../depends.ts"; +import { randomWorld, fillArray } from "./_db_helpers.ts"; + +export const headers = new Headers([ + ["server", SERVER], + ["content-type", MIME_JSON], +]); + +export default async (req: ServerRequest): Promise => { + const u = new URL(req.url, "http://deno"); + const l = Number(u.searchParams.get("queries")); + const rnd = await Promise.all(await fillArray(randomWorld(), l)); + headers.set("date", dyn_date()); + req.respond({ + headers, + body: JSON.stringify(rnd), + }); +}; diff --git a/frameworks/TypeScript/deno/src/_handlers/mongodb-raw/single-query.ts b/frameworks/TypeScript/deno/src/_handlers/mongodb-raw/single-query.ts new file mode 100644 index 00000000000..5d25c48cc2a --- /dev/null +++ b/frameworks/TypeScript/deno/src/_handlers/mongodb-raw/single-query.ts @@ -0,0 +1,16 @@ +import { ServerRequest, SERVER, dyn_date, MIME_JSON } from "../../depends.ts"; +import { randomWorld } from "./_db_helpers.ts"; + +export const headers = new Headers([ + ["server", SERVER], + ["content-type", MIME_JSON], +]); + +export default async (req: ServerRequest): Promise => { + const rnd = await randomWorld(); + headers.set("date", dyn_date()); + req.respond({ + headers, + body: JSON.stringify(rnd), + }); +}; diff --git a/frameworks/TypeScript/deno/src/_handlers/mongodb-raw/updates.ts b/frameworks/TypeScript/deno/src/_handlers/mongodb-raw/updates.ts new file mode 100644 index 00000000000..3629c95d8b7 --- /dev/null +++ b/frameworks/TypeScript/deno/src/_handlers/mongodb-raw/updates.ts @@ -0,0 +1,18 @@ +import { ServerRequest, SERVER, dyn_date, MIME_JSON } from "../../depends.ts"; +import { updateQuery, fillArray } from "./_db_helpers.ts"; + +export const headers = new Headers([ + ["server", SERVER], + ["content-type", MIME_JSON], +]); + +export default async (req: ServerRequest): Promise => { + const u = new URL(req.url, "http://deno"); + const l = Number(u.searchParams.get("queries")); + const rnd = await Promise.all(await fillArray(updateQuery(), l)); + headers.set("date", dyn_date()); + req.respond({ + headers, + body: JSON.stringify(rnd), + }); +}; diff --git a/frameworks/TypeScript/deno/src/_handlers/plaintext.ts b/frameworks/TypeScript/deno/src/_handlers/plaintext.ts new file mode 100644 index 00000000000..b91e23d4190 --- /dev/null +++ b/frameworks/TypeScript/deno/src/_handlers/plaintext.ts @@ -0,0 +1,17 @@ +import { + ServerRequest, + SERVER, + dyn_date, + MIME_TEXT, + HELLO_WORLD, +} from "../depends.ts"; + +const headers = new Headers([ + ["server", SERVER], + ["content-type", MIME_TEXT], +]); + +export default async (req: ServerRequest): Promise => { + headers.set("date", dyn_date()); + req.respond({ headers, body: HELLO_WORLD }); +}; diff --git a/frameworks/TypeScript/deno/src/depends.ts b/frameworks/TypeScript/deno/src/depends.ts new file mode 100644 index 00000000000..cd9cf9bac30 --- /dev/null +++ b/frameworks/TypeScript/deno/src/depends.ts @@ -0,0 +1,23 @@ +export type { Response } from "https://deno.land/std@0.87.0/http/server.ts"; + +export { + ServerRequest, + serve, +} from "https://deno.land/std@0.87.0/http/server.ts"; + +export { MongoClient, Bson } from "https://deno.land/x/mongo@v0.22.0/mod.ts"; + +export const SERVER: string = "Deno"; + +let date = new Date().toUTCString(); +setInterval(() => (date = new Date().toUTCString()), 850); +export const dyn_date = () => date; + +export const MIME_JSON = "application/json"; +export const MIME_HTML = "text/html; charset=utf-8"; + +export const HELLO_WORLD: Uint8Array = new TextEncoder().encode( + "Hello, World!" +); + +export const MIME_TEXT = "text/plain; charset=UTF-8"; diff --git a/frameworks/TypeScript/deno/src/handlers.ts b/frameworks/TypeScript/deno/src/handlers.ts index 7c4701990be..b95f9aee40c 100644 --- a/frameworks/TypeScript/deno/src/handlers.ts +++ b/frameworks/TypeScript/deno/src/handlers.ts @@ -1,46 +1,16 @@ -import { - ServerRequest, - Response -} from "https://deno.land/std@0.87.0/http/server.ts"; +import type { ServerRequest } from "./depends.ts"; +import JSONHandler from "./_handlers/json.ts"; +import PlaintextHandler from "./_handlers/plaintext.ts"; interface Handler { - (request: ServerRequest): Promise + (request: ServerRequest): Promise; } -const SERVER: string = "Deno"; -const HELLO_WORLD: Uint8Array = new TextEncoder().encode("Hello, World!"); - -let date: string = new Date().toUTCString(); -setInterval(() => { date = new Date().toUTCString(); }, 1000); - -const json: Handler = async (req: ServerRequest): Promise => { - const headers = new Headers([ - ["server", SERVER], - ["content-type", "application/json"], - ["date", date] - ]); - - req.respond({ - headers, - body: JSON.stringify({ message: "Hello, World!" }) - } as Response); -}; - -const plaintext: Handler = async (req: ServerRequest): Promise => { - const headers = new Headers([ - ["server", SERVER], - ["content-type", "text/plain; charset=UTF-8"], - ["date", date] - ]); - - req.respond({ headers, body: HELLO_WORLD } as Response); -}; - -const handlers: { [Key: string]: Handler } = {}; - -handlers["/json"] = json; -handlers["/plaintext"] = plaintext; +interface Handlers { + [index: string]: Handler; +} -export { - handlers +export const handlers: Handlers = { + "/json": JSONHandler, + "/plaintext": PlaintextHandler, }; diff --git a/frameworks/TypeScript/deno/src/main.ts b/frameworks/TypeScript/deno/src/main.ts index f2fc62bca18..fcb0bb562de 100644 --- a/frameworks/TypeScript/deno/src/main.ts +++ b/frameworks/TypeScript/deno/src/main.ts @@ -1,7 +1,15 @@ import { serve } from "https://deno.land/std@0.87.0/http/server.ts"; - import { handlers } from "./handlers.ts"; - for await (const req of serve("0.0.0.0:8080")) { - handlers[req.url](req); + if (handlers[req.url] != undefined) { + handlers[req.url](req).catch((e) => { + console.error(e); + Deno.exit(9); + }); + } else { + req.respond({ + body: "404 Not Found", + }); + } + continue; }