Giter Club home page Giter Club logo

actix-web's Introduction

Actix

Actor framework for Rust

crates.io Documentation Minimum Supported Rust Version License Dependency Status
CI codecov Downloads Chat on Discord

Documentation

Features

  • Async and sync actors
  • Actor communication in a local/thread context
  • Uses futures for asynchronous message handling
  • Actor supervision
  • Typed messages (No Any type)
  • Runs on stable Rust 1.68+

Usage

To use actix, add this to your Cargo.toml:

[dependencies]
actix = "0.13"

Initialize Actix

In order to use actix you first need to create a System.

fn main() {
    let system = actix::System::new();

    system.run();
}

Actix uses the Tokio runtime. System::new() creates a new event loop. System.run() starts the Tokio event loop, and will finish once the System actor receives the SystemExit message.

Implementing an Actor

In order to define an actor you need to define a struct and have it implement the Actor trait.

use actix::{Actor, Context, System};

struct MyActor;

impl Actor for MyActor {
    type Context = Context<Self>;

    fn started(&mut self, _ctx: &mut Self::Context) {
        println!("I am alive!");
        System::current().stop(); // <- stop system
    }
}

fn main() {
    let system = System::new();

    let _addr = system.block_on(async { MyActor.start() });

    system.run().unwrap();
}

Spawning a new actor is achieved via the start and create methods of the Actor trait. It provides several different ways of creating actors; for details, check the docs. You can implement the started, stopping and stopped methods of the Actor trait. started gets called when the actor starts and stopping when the actor finishes. Check the API docs for more information on the actor lifecycle.

Handle Messages

An Actor communicates with another Actor by sending messages. In actix all messages are typed. Let's define a simple Sum message with two usize parameters and an actor which will accept this message and return the sum of those two numbers. Here we use the #[actix::main] attribute as an easier way to start our System and drive our main function so we can easily .await for the responses sent back from the Actor.

use actix::prelude::*;

// this is our Message
// we have to define the response type (rtype)
#[derive(Message)]
#[rtype(usize)]
struct Sum(usize, usize);

// Actor definition
struct Calculator;

impl Actor for Calculator {
    type Context = Context<Self>;
}

// now we need to implement `Handler` on `Calculator` for the `Sum` message.
impl Handler<Sum> for Calculator {
    type Result = usize; // <- Message response type

    fn handle(&mut self, msg: Sum, _ctx: &mut Context<Self>) -> Self::Result {
        msg.0 + msg.1
    }
}

#[actix::main] // <- starts the system and block until future resolves
async fn main() {
    let addr = Calculator.start();
    let res = addr.send(Sum(10, 5)).await; // <- send message and get future for result

    match res {
        Ok(result) => println!("SUM: {}", result),
        _ => println!("Communication to the actor has failed"),
    }
}

All communications with actors go through an Addr object. You can do_send a message without waiting for a response, or you can send an actor a specific message. The Message trait defines the result type for a message.

Actor State And Subscription For Specific Messages

You may have noticed that the methods of the Actor and Handler traits accept &mut self, so you are welcome to store anything in an actor and mutate it whenever necessary.

Address objects require an actor type, but if we just want to send a specific message to an actor that can handle the message, we can use the Recipient interface. Let's create a new actor that uses Recipient.

use actix::prelude::*;
use std::time::Duration;

#[derive(Message)]
#[rtype(result = "()")]
struct Ping {
    pub id: usize,
}

// Actor definition
struct Game {
    counter: usize,
    name: String,
    recipient: Recipient<Ping>,
}

impl Actor for Game {
    type Context = Context<Game>;
}

// simple message handler for Ping message
impl Handler<Ping> for Game {
    type Result = ();

    fn handle(&mut self, msg: Ping, ctx: &mut Context<Self>) {
        self.counter += 1;

        if self.counter > 10 {
            System::current().stop();
        } else {
            println!("[{0}] Ping received {1}", self.name, msg.id);

            // wait 100 nanoseconds
            ctx.run_later(Duration::new(0, 100), move |act, _| {
                act.recipient.do_send(Ping { id: msg.id + 1 });
            });
        }
    }
}

fn main() {
    let system = System::new();

    system.block_on(async {
        // To create a cyclic game link, we need to use a different constructor
        // method to get access to its recipient before it starts.
        let _game = Game::create(|ctx| {
            // now we can get an address of the first actor and create the second actor
            let addr = ctx.address();

            let addr2 = Game {
                counter: 0,
                name: String::from("Game 2"),
                recipient: addr.recipient(),
            }
            .start();

            // let's start pings
            addr2.do_send(Ping { id: 10 });

            // now we can finally create first actor
            Game {
                counter: 0,
                name: String::from("Game 1"),
                recipient: addr2.recipient(),
            }
        });
    });

    // let the actors all run until they've shut themselves down
    system.run().unwrap();
}

Chat Example

See this chat example which shows more comprehensive usage in a networking client/server service.

Contributing

All contributions are welcome, if you have a feature request don't hesitate to open an issue!

License

This project is licensed under either of

at your option.

Code of Conduct

Contribution to the actix repo is organized under the terms of the Contributor Covenant. The Actix team promises to intervene to uphold that code of conduct.

actix-web's People

Contributors

aaron1011 avatar adwhit avatar aliemjay avatar ava57r avatar dependabot[bot] avatar doumanash avatar dowwie avatar dunnock avatar fafhrd91 avatar fakeshadow avatar fuchsnj avatar ibraheemdev avatar jesskfullwood avatar johntitor avatar jrconlin avatar kornelski avatar krircc avatar lukemathwalker avatar mattgathu avatar memoryruins avatar messense avatar mitsuhiko avatar mockersf avatar neopallium avatar niklasf avatar popzxc avatar radix avatar robjtede avatar svenstaro avatar zzau13 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

actix-web's Issues

serde_qs

discovered today this library https://docs.rs/serde_qs/0.4.0-rc. 2/serde_qs/ which allows parsing complex urls like

?name=Acme&id=42&phone=12345&address[postcode]=12345&address[city]=Carrot+City&user_ids[0]=1&user_ids[1]=2&user_ids[2]=3&user_ids[3]=4

to struct

{
    id: 42,
    name: "Acme".to_string(),
    phone: 12345,
    address: Address {
        city: "Carrot City".to_string(),
        postcode: "12345".to_string(),
    },
    user_ids: vec![1, 2, 3, 4],
};

Ami44

Example of a Handler that returns a future

I would love an example of how to return a Future to an HttpResponse.

For example using something like mysql async to make a request to a database and then compose an HttpResponse and have that been returned. Or an HTTP request via Hyper and then compose a response based on the result.

I love what you have done so far and I suspect I'm missing something obvious but I haven't been able to figure it out myself.

I would be willing to contribute an example if you point me in the right direction.

Thanks.

Request appears to hang after returning data

The following code causes web browser requests to appear to never complete despite the body having been completely downloaded. I have about 43 rows in the database.

Requests made with curl or wget function as expected.

My state looks like

struct State {
    db: SyncAddress<DbExecutor>,
    db2: SyncAddress<crud::CRUDExecutor>,
}

Handler

fn loadly(req: HttpRequest<State>) -> Box<Future<Item = HttpResponse, Error = Error>> {
    use schema::users::dsl::*;
    req.state().db2.call_fut( crud::Load::new(users.filter(id.ne(32))) )
        .from_err()
        .and_then(|res: Result<Vec<models::User>, _>| {
            match res {
                Ok(user) => {
                    println!("User: {:?}", user);
                    Ok(httpcodes::HTTPOk.build().chunked().json(user)?)
                }
                Err(_) => Ok(httpcodes::HTTPInternalServerError.into())
            }
        })
        .responder()    
}

CRUDExecutor

//! Db executor actor
use diesel;
use actix_web;
use actix::prelude::*;
use r2d2::Pool;
use r2d2_diesel::ConnectionManager;
use diesel::MysqlConnection;
use diesel::prelude::*;
use std::marker::PhantomData;

use models;
use schema;

pub struct CRUDExecutor(pub Pool<ConnectionManager<MysqlConnection>>);

pub struct Load<T, R>(pub T, pub PhantomData<R>)
where
    T: diesel::query_dsl::RunQueryDsl<MysqlConnection>
        + diesel::query_builder::Query
        + diesel::query_builder::QueryFragment<diesel::mysql::Mysql>
        + diesel::query_builder::QueryId;

impl<T, R> Load<T, R> where
    T: diesel::query_dsl::RunQueryDsl<MysqlConnection>
        + diesel::query_builder::Query
        + diesel::query_builder::QueryFragment<diesel::mysql::Mysql>
        + diesel::query_builder::QueryId {
    pub fn new(t: T) -> Self {
        Load(t, PhantomData)
    }        

}

impl<T, R> ResponseType for Load<T, R>
where
    T: diesel::query_dsl::RunQueryDsl<MysqlConnection>
        + diesel::query_builder::Query
        + diesel::query_builder::QueryFragment<diesel::mysql::Mysql>
        + diesel::query_builder::QueryId,
{
    type Item = Vec<R>;
    type Error = actix_web::error::ErrorInternalServerError<diesel::result::Error>;
}

impl Actor for CRUDExecutor {
    type Context = SyncContext<Self>;
}


impl<T, R> Handler<Load<T, R>> for CRUDExecutor
where
    T: diesel::query_dsl::RunQueryDsl<MysqlConnection>
        + diesel::query_builder::Query
        + diesel::query_builder::QueryFragment<diesel::mysql::Mysql>
        + diesel::query_builder::QueryId,
    diesel::mysql::Mysql: diesel::types::HasSqlType<<T as diesel::query_builder::Query>::SqlType>,
    (i32, String): diesel::Queryable<<T as diesel::query_builder::Query>::SqlType, diesel::mysql::Mysql>,
    R: diesel::Queryable<<T as diesel::query_builder::Query>::SqlType, diesel::mysql::Mysql>
{
    fn handle(&mut self, msg: Load<T, R>, _: &mut Self::Context) -> Response<Self, Load<T, R>> {
        // use self::schema::users::dsl::*;
        let conn = self.0.get().unwrap();

        match msg.0.load::<R>(&*conn) {
            Ok(items) => Self::reply(items),
            Err(err) => Self::reply_error(actix_web::error::ErrorInternalServerError(err)),
        }
    }
}

Diesel Schema

table! {
    users (id) {
        id -> Integer,
        name -> Text,
    }
}

req.query inside future

Hello

i have this route (POST) "/name/{name}" to match "/name/aaa?token=xxxxxxxxxxx"
i try to get data inside path (ok) AND query (ko) AND body (ok)

fn action(mut req: HttpRequest) -> Box<Future<Item=HttpResponse, Error=Error>> { // println!("{:?}", req);
    let name: String = req.match_info().query("name").unwrap(); // <== OK, i get "aaaa"
    let query:HashMap<Cow<str>, Cow<str>> = req.query(); println!("{:?}", query); // <== KO, if i add this line
    req.payload_mut().readany() .... <== OK, i get body 

build error

error[E0502]: cannot borrow `req` as mutable because it is also borrowed as immutable
   --> src/main.rs:84:5
    |
73  |     let rawquery:HashMap<Cow<str>, Cow<str>> = req.query(); println!("{:?}", rawquery);
    |                                                --- immutable borrow occurs here
...
84  |     req.payload_mut().readany()
    |     ^^^ mutable borrow occurs here
...
129 | }
    | - immutable borrow ends here

But if set fn action(req: HttpRequest) i have another error.

How extract query params (when i need also path and body) - see nothing in doc.
Thanks

Ranges header support

This week I took a deep dive in the RFC and thought about the possibilites. I have a solution now, but I don't feel it's complete, so I need your advice about the implementation.

RFC defines two types of response when the ranges header is present: a simple one, and when you request multiple ranges which must give you back a "Multipart" response.

Implementing the latter one has the advantage of fully conforming the RFC, but has security implications(overlapping ranges, etc). The former one is much easier if you modify the Responder. In most cases it's enough. You can watch&seek a movie in your browser, also you can get a working ipxe server(this was my goal with this). Implementing this for the NamedFIle is trivial, but what if we need the ranges support for files when they come from another location.(database like MongoDB or CouchDB, S3, another webserver etc) In this case it's maybe easier to add the support in a main component.

What do you think about this and which is the preferred way for this project?

web site draft

http://tmpxqsddkjqlkdjlqkjdlqkdjqlkjd.surge.sh/

I know the http://ejs.co/ site which is based on a free template proposed by https://themes.3rdwavemedia.com/. I quickly adapted this template (draft) for actix-web: see the real demo http://tmpxqsddkjqlkdjlqkjdlqkdjqlkjd.surge.sh/

I will remove the demo site within a week and if you are interested then copy the content to the temporary repository https://github.com/ami44/actix-web-ami44-site

Thank you for your help this week, my vacation is over and I will be less present.
good continuation

examples/tls

cargo run ok but error when use

thread 'arbiter:"a097acc7-af55-43b7-ba0f-61b256b68092":"actor"' panicked at 'called `Result::unwrap()` on an `Err` value: InvalidHeaderValueBytes(InvalidHeaderValue { _priv: () })', /checkout/src/libcore/result.rs:906:4
note: Run with `RUST_BACKTRACE=1` for a backtrace.

signal not close postgresql client

Hello

actor do not close automatically postgresql conn after shutting down the actix-web application.

When a start application, i mount 12 clients

let db_url = "postgres://postgres:azerty@localhost:5432/test";
let addr = SyncArbiter::start(num_cpus::get() * 3, move || db::DbExecutor::new(&db_url));

...

// (db.rs)
impl DbExecutor {
    pub fn new(db_url: &str) -> DbExecutor {
        DbExecutor{
            conn : match Connection::connect(db_url, TlsMode::None) {
                Err(err) => panic!("Error connecting to {} {:?}", db_url, err),
                Ok(conn) => conn
            }
        }
    }
}

I can count 12 clients with this sql cmd number-of-active-connections-and-remaining-connections

select max_conn,used,res_for_super,max_conn-used-res_for_super res_for_normal
from
  (select count(*) used from pg_stat_activity) t1,
  (select setting::int res_for_super from pg_settings where name=$$superuser_reserved_connections$$) t2,
  (select setting::int max_conn from pg_settings where name=$$max_connections$$) t3;

If now i send ctrl+c, application stop (ok) and rerun sql cmd, i see always 12 connections (ko). If a rerun actix-web application i have 24 clients connections. etc.

#17 , you said btw usually you don't need explicit disconnect in rust, usually connections get closed on "drop".

What would be the solution to close also the postgresql connections after a signal ?

Address already in use

Hello

I test a little app and i use cargo-watch as cargo watch -x run : it's work but often i have thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: Error { repr: Os { code: 98, message: "Address already in use" } }', /checkout/src/libcore/result.rs:906:4

And i wait (1mn) ... and after it's restart

actix does not seem to release the listened port correctly (after a SIGTERM for example).

But then how to close a connection to a database or use actix-web with kubernetes like (https://blog.risingstack.com/graceful-shutdown-node-js-kubernetes/).

Have you an example to properly close actix-web.
Thank

Actix module error is private

Trying to use the basic example again, I get the following:

error[E0603]: module `error` is private
 --> src/main.rs:8:5
  |
8 | use actix_web::error::Result;
  |     ^^^^^^^^^^^^^^^^^^^^^^^^

[Low prio/question] deserialize ws::Message::Binary with bincode?

Hello!

I have a websocket working and would like to deserialize the message I get.

    impl Handler<ws::Message> for MyWebSocket {
        type Result = ();

        fn handle(&mut self, msg: ws::Message, ctx: &mut Self::Context) {
            println!("WS received {:?}", msg);

            match msg {
                ws::Message::Ping(msg) => ctx.pong(&msg),
                ws::Message::Text(text) => ctx.text(&format!("Websocket received text: {}", text)),
                ws::Message::Binary(bin) => {
                    let decoded: Test = deserialize(&bin[..]).unwrap();
                    println!("Received a binary message {:?}", decoded);

                    ctx.binary(bin)
                },
                ws::Message::Closed | ws::Message::Error => ctx.stop(),
                _ => (),
            }
        }
    }

Sadly that doesn't compile, because: > error[E0608]: cannot index into a value of type actix_web::Binary

Now what I did to fix this, is add another match, like so:

match bin {
                    actix_web::Binary::Bytes(b) => {
                        let decoded: Test = deserialize(&b[..]).unwrap();
                        println!("Received a binary message {:?}", decoded);
                        ctx.binary(b)
                    },
                    _ => ()
                }

That works, for my case but doesn't seem too elegant.
Isn't there any generic way to access the insides of the Binary?

json-rust

Hello

I would like to use json-rust (light and fast https://github.com/serde-rs/json-benchmark) instead of serde_json. I found example #2 https://actix.github.io/actix-web/guide/qs_7. html#json-request you can manually load payload into memory and ther deserialize it. Here is simple example. ....

I copied/paste the code into the file the example actix-web-master/examples/json/src/main. rs and I have several errors:

I've fixed fn index (mut req: HttpRequest) -> Future<Item=HttpResponse, Error=Error=Error> {```` in fn index (mut req: HttpRequest) -> Box<Future<Item=HttpResponse, Error=Error>>>> {`` but then I have the error

error[E0599]: no method named `concat2` found for type `actix_web:: payload:: ReadAny` in the current scope
  src/main. rs: 29:32
   |
29 | req. payload_mut (). readany (). concat2 ()
   | ^^^^^^^
   |
   = help: items from traits can only be used if the trait is in scope
   = note: the following trait is implemented but not in scope, perhaps add a `use' for it:
           candidate #1: `future:: Stream; `

Could you fix this example in the documentation and add an example that works in actix-web-master/examples/json/src/main. rs.

Sorry, I'm really a beginner
Thank you

postgresql handler

Hello

Thank for your diesel example. I adapted it to use rust-postgres ... but i don't know how to point to the open connection inside Handler :-)

use std::io;
use actix_web::*;
use actix::prelude::*;
use postgres::{Connection, TlsMode};

pub struct DbExecutor(Connection);

impl Actor for DbExecutor {
    type Context = SyncContext<Self>;
}

impl DbExecutor {
    pub fn new(db_url: &str) -> DbExecutor {
        DbExecutor(
            /*let conn =*/ match Connection::connect(db_url, TlsMode::None) {
                Err(err) => panic!("Error connecting to {} {:?}", db_url, err),
                Ok(conn) => conn
            }
        )
    }
}

...

impl Handler<CreateUser> for DbExecutor {
    fn handle(&mut self, msg: CreateUser, _: &mut Self::Context)
              -> Response<Self, CreateUser>
    {

        // let rows = &conn.query("SELECT 1;", &[]).unwrap(); // println!("{:?}", rows); <== how point to conn

        Self::reply("Hello".to_string())
    }
}

Thank for your help

How to handle application/json?

First of, let me say: thanks for your time and all the effort you put into actix-web!

Secondly, my question would be considering json post requests. How would you handle them? Could you give an example?

Can't have multiple Applications on a single server with different state

I don't think this is currently possible, but please correct me if I'm wrong.

HttpServer::new() requires an iterator of Applications (something that implements IntoHttpHandler)

Since the Application has a generic State parameter, if you have applications with a different type for State, you can't create an iterator over these different types.

"Signal" feature doesn't compile

#....................
actix = "^0.3.5"
actix-web = { git = "https://github.com/actix/actix-web.git", version = "0.3.0",  features = ["signal"] }


//....................
use actix_web::*;

#[cfg(unix)]
use actix::actors::signal::{ProcessSignals, Subscribe};


//....................
let signals = Arbiter::system_registry().get::<ProcessSignals>();
signals.send(Subscribe(addr.subscriber()));

===============>

error[E0433]: failed to resolve. Use of undeclared type or module `Arbiter`
  --> src/main.rs:73:19
   |
73 |     let signals = Arbiter::system_registry().get::<ProcessSignals>();
   |                   ^^^^^^^ Use of undeclared type or module `Arbiter`

Issue with JSON Encoded Responses

If I have a handler such as the one below

#[derive(Serialize, Queryable, Debug)]
pub struct User {
    pub id: i32,
    pub name: String,
}
fn loadly(req: HttpRequest<State>) -> Box<Future<Item = HttpResponse, Error = Error>> {
    let userv: Vec<models::User> = vec![models::User{id: 1, name: "rabbit".to_owned()},
    models::User{id: 2, name: "rabbit".to_owned()},
    models::User{id: 3, name: "rabbit".to_owned()},
    models::User{id: 4, name: "rabbit".to_owned()}
    ];
    Box::new(futures::future::ok(httpcodes::HTTPOk.build().chunked().json(userv).unwrap()))
}

The response ends up being the following

HTTP/1.1 200 OK
content-length: 011
content-type: application/json
date: Tue, 02 Jan 2018 20:55:42 GMT

Body
[{"id":1,"n

Basic Example does not compile

The Basic Example does not appear to compile, with the following error:

error[E0277]: the trait bound `actix_web::Body: std::convert::From<std::string::String>` is not satisfied
  --> src/main.rs:20:10
   |
20 |         .body(format!("Hello {}!", req.match_info().get("name").unwrap()))
   |          ^^^^ the trait `std::convert::From<std::string::String>` is not implemented for `actix_web::Body`
   |
   = note: required because of the requirements on the impl of `std::convert::Into<actix_web::Body>` for `std::string::String`

Using main.rs equal to the basic example and a Cargo.toml that looks like:

[package]
name = "actix_test"
version = "0.1.0"

[dependencies]
actix = "*"
actix-web = "*"
env_logger = "*"

Proposal: Logo

I think a beautigul Logo is missing for the project.
so i make one and 3 colors.


app state & session

i try this example https://actix.github.io/actix-web/guide/qs_3.html#state
it's OK but i want also set session

fn index(req: HttpRequest<AppState>) -> String {
    let count = req.state().counter.get() + 1;
    req.state().counter.set(count);
    req.session().set("token", "xxxxxxxxxx".to_owned() )?; // <==== KO
    format!("Request number: {}", count)
}

fn main() {
    Application::with_state(AppState{counter: Cell::new(0)})
        .resource("/", |r| r.method(Method::GET).f(index))
        .finish();
}

Err

error[E0599]: no method named `session` found for type `actix_web::HttpRequest<AppState>` in the current scope

How get state and session in this example ?
Thank

build error ring-asm

cd licorne && cargo clean && cargo update && cargo build

error: Multiple packages link to native library `ring-asm`. A native library can be linked only once.

Package `ring v0.12.1`
    ... which is depended on by `cookie v0.10.1`
    ... which is depended on by `actix-web v0.3.2 (https://github.com/actix/actix-web#a7c24aac)`
    ... which is depended on by `licorne v0.1.0 (file:///C:/Users/ami44/Documents/licorne)`
links to native library `ring-asm`.

Package `ring v0.13.0-alpha`
    ... which is depended on by `cookie v0.11.0-dev (https://github.com/alexcrichton/cookie-rs.git#8579b4b7)`
    ... which is depended on by `actix-redis v0.1.0 (https://github.com/actix/actix-redis#abb6c6ba)`
    ... which is depended on by `licorne v0.1.0 (file:///C:/Users/ami44/Documents/licorne)`
also links to native library `ring-asm`.

Getting Started

Hello

I discover actix-web. When I follow the instructions of the example https://actix.github.io/actix-web/guide/qs_2. html with this code

fn main () {

    let sys = actix:: System:: new ("example");

    let app = Application:: new ()
        . resource ("/", |r| r. f (index)
        . finish ();

    HttpServer:: new (|| app)
        . bind ("127.0.0.0.1:8088"). unwrap ()
        . start ();

}

then I have the mistake

HttpServer:: new (|| app)
^^^^^^^^^^^^^^^^^^^^^^`actix_web:: application:: HttpApplication` is not an iterator; maybe try calling ``iter ()` or a similar method

How to compile the code HttpServer:: new (|| app) without error?

The final example works but is not consistent with the first steps indicated.

Thank you

System is not running with actix 0.4.2 and actix-web 0.3.0 (minimal example)

So I updated actix and actix-web today by deleting my Cargo.lock and updating again.

I got this in my Cargo.toml

actix = { git = "https://github.com/actix/actix" }
actix-web = { git = "https://github.com/actix/actix-web" }

and this in my Cargo.lock

dependencies = [
 "actix 0.4.2 (git+https://github.com/actix/actix)",
 "actix-web 0.3.0 (git+https://github.com/actix/actix-web)",
...
]

Now this minimal example:

fn main() {
    let url = "localhost:8000";

    let sys = actix::System::new("test");
    let _server = HttpServer::new(
        || Application::new()
            .resource("/", |r| r.f(index))
              )
        .bind(url).unwrap()
        .start();

    let _ = sys.run();
}

fn index(req: HttpRequest) -> &'static str {
    "Hurray!"
}

gives me:

thread 'main' panicked at 'System is not running', /home/unmoving/.cargo/registry/src/github.com-1ecc6299db9ec823/actix-0.4.2/src/arbiter.rs:143:21
stack backtrace:
0: std::sys::unix::backtrace::tracing::imp::unwind_backtrace
at libstd/sys/unix/backtrace/tracing/gcc_s.rs:49
1: std::sys_common::backtrace::print
at libstd/sys_common/backtrace.rs:68
at libstd/sys_common/backtrace.rs:57
2: std::panicking::default_hook::{{closure}}
at libstd/panicking.rs:381
3: std::panicking::default_hook
at libstd/panicking.rs:397
4: std::panicking::rust_panic_with_hook
at libstd/panicking.rs:577
5: std::panicking::begin_panic
at /checkout/src/libstd/panicking.rs:538
6: actix::arbiter::Arbiter::system::{{closure}}
at /home/unmoving/.cargo/registry/src/github.com-1ecc6299db9ec823/actix-0.4.2/src/arbiter.rs:143
7: <std::thread::local::LocalKey>::try_with
at /checkout/src/libstd/thread/local.rs:377
8: <std::thread::local::LocalKey>::with
at /checkout/src/libstd/thread/local.rs:288
9: actix::arbiter::Arbiter::system
at /home/unmoving/.cargo/registry/src/github.com-1ecc6299db9ec823/actix-0.4.2/src/arbiter.rs:141
10: actix::arbiter::Arbiter::new
at /home/unmoving/.cargo/registry/src/github.com-1ecc6299db9ec823/actix-0.4.2/src/arbiter.rs:58
11: actix::arbiter::Arbiter::start
at /home/unmoving/.cargo/registry/src/github.com-1ecc6299db9ec823/actix-0.4.2/src/arbiter.rs:196
12: <actix_web::server::HttpServer<T, A, H, U>>::start_workers
at /home/unmoving/.cargo/git/checkouts/actix-web-02c803d355aed967/584d0c9/src/server.rs:286
13: <actix_web::server::HttpServer<tokio_core::net::tcp::TcpStream, std::net::addr::SocketAddr, H, U>>::start
at /home/unmoving/.cargo/git/checkouts/actix-web-02c803d355aed967/584d0c9/src/server.rs:353
14: rust_actix_test::main
at src/main.rs:89
15: std::rt::lang_start::{{closure}}
at /checkout/src/libstd/rt.rs:74
16: std::panicking::try::do_call
at libstd/rt.rs:59
at libstd/panicking.rs:480
17: __rust_maybe_catch_panic
at libpanic_unwind/lib.rs:102
18: std::rt::lang_start_internal
at libstd/panicking.rs:459
at libstd/panic.rs:365
at libstd/rt.rs:58
19: std::rt::lang_start
at /checkout/src/libstd/rt.rs:74
20: main
21: __libc_start_main
22: _start

I can't seem to find the reason. Any ideas?

Complete example now at: https://github.com/Unmoving/actix-web-test/tree/master

Hello world - a few compilation errors

This

extern crate actix_web;

use actix_web::*;

fn index(req: HttpRequest) -> String {
    format!("Hello {}!", &req.match_info()["name"])
}

fn main() {
    HttpServer::new(
        || Application::new()
            .resource("/{name}", |r| r.f(index)))
        .bind("127.0.0.1:8080")?
        .start();
}

gives this

$ cargo build
   Compiling my_webapp v0.1.0 (file:///home/alex/projects/rust/my_webapp)
error[E0608]: cannot index into a value of type `&actix_web::Params`
 --> src/main.rs:6:27
  |
6 |     format!("Hello {}!", &req.match_info()["name"])
  |                           ^^^^^^^^^^^^^^^^^^^^^^^^

error[E0599]: no function or associated item named `new` found for type `actix_web::Application<_>` in the current scope
  --> src/main.rs:11:12
   |
11 |         || Application::new()
   |            ^^^^^^^^^^^^^^^^ function or associated item not found in `actix_web::Application<_>`

error[E0624]: method `bind` is private
  --> src/main.rs:13:10
   |
13 |         .bind("127.0.0.1:8080")?
   |          ^^^^                                                                                                                                            
                                                                                                                                                              
error[E0277]: the `?` operator can only be used in a function that returns `Result` (or another type that implements `std::ops::Try`)                         
  --> src/main.rs:10:5                                                                                                                                        
   |                                                                                                                                                          
10 |        HttpServer::new(                                                                                                                                  
   |   _____-                                                                                                                                                 
   |  |_____|                                                                                                                                                 
   | ||                                                                                                                                                       
11 | ||         || Application::new()                                                                                                                         
12 | ||             .resource("/{name}", |r| r.f(index)))                                                                                                     
13 | ||         .bind("127.0.0.1:8080")?                                                                                                                      
   | ||                                -                                                                                                                      
   | ||________________________________|                                                                                                                      
   | |_________________________________cannot use the `?` operator in a function that returns `()`                                                            
   |                                   in this macro invocation                                                                                               
   |                                                                                                                                                          
   = help: the trait `std::ops::Try` is not implemented for `()`                                                                                              
   = note: required by `std::ops::Try::from_error`                                                                                                            
                                                                                                                                                              
error: aborting due to 4 previous errors

error: Could not compile `my_webapp`.

Hello actix

Hello

I discover your actix-web project and this one seems really promising. Can be as promising as the nodesjs/express framework (easy, cool, fast, documented...).

Is there a minimal example to use a third tokio module (https://tokio.rs/docs/going-deeper-tokio/third-party/) to call curl, postgres, cassandra... in a road function? is that even possible?

Thank you

CORS middleware: allowed_headers is defaulting to None

The documentation for CorsBuilder::allowed_headers() says

If All is set, whatever is requested by the client in Access-Control-Request-Headers will be echoed back in the Access-Control-Allow-Headers header.
...
Defaults to All.

The code is correctly defaulting the internal headers value to All, but there is no code actually echoing back the Access-Control-Request-Headers, it just leaves the Access-Control-Allow-Headers header empty.

relevant line of code generating the response:
https://github.com/actix/actix-web/blob/master/src/middleware/cors.rs#L303

postgresql performance

Hello - Is not an issue

I found your example diesel/postgresql added to FrameworkBenchmarks.

I'm surprised that you don't usetokio-postgres orr2d2-postgres - Using an ORM always means sacrificing a little bit of performance for a little bit of ease. Have you ever made a performance comparison that decided on the choice of "diesel"?

Thank

slog

Hello

I use slog + AppState ... and it's ok ! Now i have colored term info (and i can also write json to a file with slog ...) . See my first code .

But i have a problem with Actor with lifetime : See my second code

error[E0106]: missing lifetime specifier
  --> src/db.rs:45:59
   |
45 | pub struct CreateUserWithLog { pub name: String, pub log: &Logger}
   |                                                           ^ expected lifetime parameter

error: aborting due to previous error

first code src/main.rs (ok)

#[macro_use]
extern crate slog;
extern crate slog_term;
extern crate slog_async;
extern crate slog_envlogger;
extern crate slog_stream;
use slog::Drain;
use slog::Logger;
...
struct AppState {
    db: SyncAddress<DbExecutor>,
    log: Logger,
}
...
fn index(mut req: HttpRequest<AppState>) -> Box<Future<Item=HttpResponse, Error=Error>> {
    let _log = &req.state().log;
    debug!(_log, "Hello {}", "slog"); // OK !
    ...
}
...
fn main() {
    ::std::env::set_var("RUST_LOG", "actix_web=info");
    let _guard = slog_envlogger::init().unwrap(); // replace ``env_logger::init();``
    let decorator = slog_term::TermDecorator::new().build();
    let console_drain = slog_term::FullFormat::new(decorator).build().fuse();
    let console_drain = slog_async::Async::new(console_drain).build().fuse();
    let _log = slog::Logger::root(console_drain, o!());
    ...
    let addr = HttpServer::new(
        move || Application::with_state(AppState{
                db: addr.clone(),
                log: _log.clone(),
            })
    ...
}

second code (with error &Logger=> ^ expected lifetime parameter)

// db.rs
use std::io;
use actix_web::*;
use actix::prelude::*;
use slog::Logger;
...
pub struct CreateUserWithLog { pub name: String, pub log: &Logger}
impl ResponseType for CreateUserWithLog { type Item = String; type Error = Error; }
impl Handler<CreateUserWithLog> for DbExecutor {
    fn handle(&mut self, msg: CreateUserWithLog, _: &mut Self::Context)
              -> Response<Self, CreateUserWithLog>
    {
        println!("*** {}", &msg.name);
        Self::reply("Hello".to_string())
    }
}

// main.rs
fn index(mut req: HttpRequest<AppState>) -> Box<Future<Item=HttpResponse, Error=Error>> {

    let _log = &req.state().log; // ok
    debug!(_log, "Hello {}", "slog");  // ok

    req.state().db.call_fut(CreateUserWithLog{name: "hello name".to_owned(), log: &req.state().log})
        .from_err()
        .and_then(|res| {
            Ok(HttpResponse::build(StatusCode::OK)
                .content_type("text/html; charset=utf-8")
                .body("<html>Hello PG</html>").unwrap())
        })
        .responder()

I'm not yet comfortable with the lifetime of the rust language: how do I point to slog in this synchronous actor CreateUserWithLog?
Thank

missing middleware

actix-web is young but I think it has great potential. One important piece missing when choosing a framework is the management of authentication. I invite you to take inspiration from https://github.com/jaredhanson/passport: it is an indispensable middleware when developing a website quickly with authentication.

With this generic middleware you should capture the majority of developers who want to make a website in rust.

You are also missing a nice web page like https://rocket.rs (maybe your company can help you?)

Bye, Happy New Year

Actix and Actix Web always recompile on cargo build

When using Actix and Actix Web as dependencies in a project, running cargo build triggers them to recompile every time.

I.e, running cargo new --bin actix_test with the following Cargo.toml :

[package]
name = "actix_test"
version = "0.1.0"

[dependencies]
actix = "*"
actix-web = "*"

Running cargo build will always trigger a rebuild:

$ cargo build
   Compiling actix v0.3.0
   Compiling actix-web v0.1.0
   Compiling actix_test v0.1.0 (file:///<path_to_dir>/actix_test)
    Finished dev [unoptimized + debuginfo] target(s) in 4.89 secs

HEAD responses can contain body

I find this library awesome, the API is much cleaner and easier to work with than other web frameworks which utilising async operations. My only blocking issue is the lack of support for ranges and RFC compilant HEAD responses. Former one is more like an inconvenience, but the latter one is more problematic since seemingly I can't work around it.

HEAD requests are special since their responses will contain the "content-length", but body will always be empty. I can't override the content-length(framework calculates it for me, which is nice) but in this case it would be a must. Another workaround is preparing a body, then throwing it away is not efficient solution.

I'm not a seasoned developer so maybe I overlooked something, if this is the case can you point me out what I missed? Thanks!

gracefull shutdown

  • Given browser try to load a content
  • And keep open connexion to application (because content-length is not exact by example)
  • When i shutdown actix-web application
  • Then application stop
  • But thread actor keep alive (because open by browser)
  • And browser continue to wait
  • And i have "Adress is already use" when i restart application

examples/basic : #30

With firefox or chrome: html not finish to load (because content-length seem not exact).

session name & example

Hello

We can set cookie path, domain, secure ... but not name : always actix_session. Can you add a method to modify it?

If you have an example to manage database sessions (with tokio-redis or tokio-postgres) I would be interested to find example inside example/basic.rs (login/logout)

Thanks

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.