Trouble configuring Rust's Warp Filters - filter

I'm trying to setup a simple GET filter, but I'm having trouble getting it to compile.
This is the function I'm trying to map to the request:
pub async fn get_users(reference_counter: Arc<RwLock<MysqlConnection>>) -> Result<impl Reply, Rejection> {
// Get users code here
}
This is how I map the function to the GET request in main.rs:
#[tokio::main]
async fn main() {
let db_connection = storage::establish_connection();
let lock = RwLock::new(db_connection);
let reference_counter = Arc::new(lock);
let ref_filter = warp::any().map(move || reference_counter.clone());
let get_users = warp::get()
.and(warp::path("users"))
.and(ref_filter.clone())
.and_then(user::get_users);
warp::serve(get_users).run(([127, 0, 0, 1], 3030)).await;
}
The compile error happens on and_then, it's pretty cryptic and this what it says:
error[E0599]: no method named `and_then` found for struct `warp::filter::and::And<warp::filter::and::And<impl warp::filter::Filter+std::marker::Copy, warp::filters::path::Exact<warp::filters::path::internal::Opaque<&str>>>, warp::filter::map::Map<impl warp::filter::Filter+std::marker::Copy, [closure#src\main.rs:17:39: 17:72 reference_counter:_]>>` in the current scope
--> src\main.rs:21:14
|
21 | .and_then(user::get_users);
| ^^^^^^^^ method not found in `warp::filter::and::And<warp::filter::and::And<impl warp::filter::Filter+std::marker::Copy, warp::filters::path::Exact<warp::filters::path::internal::Opaque<&str>>>, warp::filter::map::Map<impl warp::filter::Filter+std::marker::Copy, [closure#src\main.rs:17:39: 17:72 reference_counter:_]>>`
|
::: C:\Users\Yasmani\.cargo\registry\src\github.com-1ecc6299db9ec823\warp-0.2.3\src\filter\and.rs:12:1
|
12 | pub struct And<T, U> {
| --------------------
| |
| doesn't satisfy `_: warp::filter::FilterBase`
| doesn't satisfy `_: warp::filter::Filter`
|
= note: the method `and_then` exists but the following trait bounds were not satisfied:
`warp::filter::and::And<warp::filter::and::And<impl warp::filter::Filter+std::marker::Copy, warp::filters::path::Exact<warp::filters::path::internal::Opaque<&str>>>, warp::filter::map::Map<impl warp::filter::Filter+std::marker::Copy, [closure#src\main.rs:17:39: 17:72 reference_counter:_]>>: warp::filter::FilterBase`
which is required by `warp::filter::and::And<warp::filter::and::And<impl warp::filter::Filter+std::marker::Copy, warp::filters::path::Exact<warp::filters::path::internal::Opaque<&str>>>, warp::filter::map::Map<impl warp::filter::Filter+std::marker::Copy, [closure#src\main.rs:17:39: 17:72 reference_counter:_]>>: warp::filter::Filter`
`&warp::filter::and::And<warp::filter::and::And<impl warp::filter::Filter+std::marker::Copy, warp::filters::path::Exact<warp::filters::path::internal::Opaque<&str>>>, warp::filter::map::Map<impl warp::filter::Filter+std::marker::Copy, [closure#src\main.rs:17:39: 17:72 reference_counter:_]>>: warp::filter::FilterBase`
which is required by `&warp::filter::and::And<warp::filter::and::And<impl warp::filter::Filter+std::marker::Copy, warp::filters::path::Exact<warp::filters::path::internal::Opaque<&str>>>, warp::filter::map::Map<impl warp::filter::Filter+std::marker::Copy, [closure#src\main.rs:17:39: 17:72 reference_counter:_]>>: warp::filter::Filter`
`&mut warp::filter::and::And<warp::filter::and::And<impl warp::filter::Filter+std::marker::Copy, warp::filters::path::Exact<warp::filters::path::internal::Opaque<&str>>>, warp::filter::map::Map<impl warp::filter::Filter+std::marker::Copy, [closure#src\main.rs:17:39: 17:72 reference_counter:_]>>: warp::filter::FilterBase`
which is required by `&mut warp::filter::and::And<warp::filter::and::And<impl warp::filter::Filter+std::marker::Copy, warp::filters::path::Exact<warp::filters::path::internal::Opaque<&str>>>, warp::filter::map::Map<impl warp::filter::Filter+std::marker::Copy, [closure#src\main.rs:17:39: 17:72 reference_counter:_]>>: warp::filter::Filter`
I believe it has something to do with the type being returned by the closure in ref_filter not matching the type expected by the function get_users, but I'm not sure why. I believe the closure returns an Arc<RwLock<MysqlConnection>>> and the get_users function takes the same. What is the problem?

The problem is that the return type of your closure is not known for some reason. Looking closely at the compiler error, the return type of your closure is _. This causes the return type of the following part of your GET filter not to be Filter, which in turn means that and_then() is not implemented.
let get_users = warp::get()
.and(warp::path("users"))
.and(ref_filter.clone())
Solution
Annotate the return type of your closure.
let ref_filter = warp::any().map(move || -> Arc<RwLock<MysqlConnection>> {reference_counter.clone()});
(Maybe you'll find out that the type of db_connection is not what you expect.)
Context
It seems to me like the type of db_connection is really the root of your problem. I tried to create a MWE from your code by substituting an empty struct or an impl Foo for db_connection, but it compiled without any issues.

The issue is that MysqlConnection from the Diesel APIs does not implement some trait that the Warp APIs require. The solution is to stop using the MysqlConnection type directly here, and use a ConnectionPool that generates connections on the fly instead. ConnectionPool is part of the r2d2 feature of the Diesel package.
Now that I think about it, it makes perfect sense. Before, I was using a single database connection to process all incoming HTTP requests. This is bad, because the app could end up making multiple read operations on the same connection at the same time.
So, here is the function processing the HTTP request:
type ConnectionPool = Pool<ConnectionManager<MysqlConnection>>;
type ConnectionLock = RwLock<ConnectionPool>;
type ConnectionLockArc = Arc<ConnectionLock>;
pub async fn get_users(lock: ConnectionLockArc) -> Result<impl Reply, Rejection>{
let users = storage::get_users(&lock);
let response = json(&users);
return Ok(response);
}
And here is how it's setup with the Warp APIs:
#[tokio::main]
async fn main() {
let pool = storage::establish_connection_pool();
let lock = RwLock::new(pool);
let reference = Arc::new(lock);
let resources = warp::any().map(move || reference.clone());
let get_users = warp::get()
.and(warp::path("users"))
.and(resources.clone())
.and_then(user::get_users);
warp::serve(get_users).run(([127, 0, 0, 1], 3030)).await;
}

Related

How to change the block timestamp in near_sdk_sim?

I need to change the block_timestamp to test timed voting.
Using VMContext, block_timestamp is changed using:
context.block_timestamp = get_timestamp();
testing_env!(context.clone());
How to do that in near_sdk_sim?
let (root, contract) = deploy_contract();
// Change the block_timestamp
Runtime has block_timestamp(), not sure how to use it.
// You should start with the master_account returned by init_simulator
// You can change the genesis config by giving
// near_sdk_sim::runtime::GenesisConfig to init_simulator instead of None
// FYI, the default value of block timestamp was 0 with None
let master_account = init_simulator(None);
// If you don't wrap this code block below in brackets
// or don't call it as a function from outside,
// you will encounter the error 'already borrowed: BorrowMutError'.
{
let mut runtime = master_account.borrow_runtime_mut();
// In near_sdk_sim, 1 block takes 1 second !
// So it changes the block timestamp 0 to 10000000000
runtime.produce_blocks(10u64);
}

Function with record as argument

I know this is very basic, but it's driving me up a wall:
peercert is defined as:
peercert(Socket) -> {ok, Cert} | {error, Reason}
Types
Socket = sslsocket()
Cert = binary()
The peer certificate is returned as a DER-encoded binary. The certificate can be decoded with public_key:pkix_decode_cert/2.
Ok, great. sslsocket is defined as -record(sslsocket, {fd = nil, pid = nil})
So I run :
New = #sslsocket{pid = Pid},
io:fwrite("~n~npeercert~p~n~n", [ssl:peercert(New)]).
But I get an error that
no function clause matching ssl:peercert({sslsocket,<0.1277.0>,undefined})
So I run it with Pid as an argument and get a similar error:
no function clause matching ssl:peercert(<0.1277.0>)
I'm totally stumped here. I had it working before, the function says it takes these as arguments...
Thank you for your help in advance!
sslsocket() type is not a record called sslsocket, otherwise it would be written as #sslsocket{}. It's a "black box type" (its real type is an implementation detail), but you can obtain it from function ssl:connect().

XPC Service returning NSAttributtedString

I have a huge problem to transfer NSAttributtedString in a block callback from XPC service.
I am trying to return basic string as:
NSDictionary *arrayComa = #{NSForegroundColorAttributeName:[NSColor colorWithRGB:0xD35250],
NSFontAttributeName:[NSFont fontWithName:#"Monaco" size:11]};
NSMutableAttributedString *testString = [[NSMutableAttributedString alloc] initWithString:#"{}" attributes:arrayComa];
I have also whitelisted the incoming response as:
let incommingClasses:Set = Set(arrayLiteral: [NSMutableAttributedString.self, NSAttributedString.self, NSColor.self, NSFont.self, NSString.self, ])
connectionService.remoteObjectInterface?.setClasses(incommingClasses, forSelector: attributtedText:withReply:, argumentIndex: 0, ofReply: true)
What ever I do I get Errors:
Exception caught during decoding of received reply to message 'Exception caught during decoding of received reply to message 'attributtedText:withReply':, dropping incoming message and calling failure block.
Exception: Exception while decoding argument 0 (#1 of invocation):
<NSInvocation: 0x6000006649c0>
return value: {v} void
target: {#?} 0x0 (block)
argument 1: {#"NSMutableAttributedString"} 0x0
Exception: value for key '<no key>' was of unexpected class 'NSMutableAttributedString'. Allowed classes are '{(
(
NSMutableAttributedString,
NSAttributedString,
NSColor,
NSFont,
NSString
)
)}'.
Anybody has transferred NSAttributtedText via XPC Service succesfully?
EDIT: I got a reply to my message on devforums, a workaround is to use an NSSet and to cast it as Set when passing to to setClasses(). Another issue is that there already are pre-set classes for all selectors, and therefore you need to add your own to the current ones, rather than set yours only. Here's a working code :
let interface = NSXPCInterface(withProtocol: MyProtocol.self)
let expectedClasses = NSSet.setWithArray([[NSMutableAttributedString.self, NSAttributedString.self, NSColor.self, NSFont.self])
let currentExpectedClasses = interface.classesForSelector("attributtedText:withReply:", argumentIndex: 0, ofReply: false) as NSSet
let allClasses = currentExpectedClasses.setByAddingSet(expectedClasses)
interface.setClasses(allClasses as Set<NSObject>, forSelector: "attributtedText:withReply:", argumentIndex: 0, ofReply: false)
Original answer :
This will only be a partial answer as I haven't found the right way to do this either yet, but
let incommingClasses:Set = Set(arrayLiteral: [NSMutableAttributedString.self, NSAttributedString.self, NSColor.self, NSFont.self, NSString.self, ])
returns a Set<NSArray>, which is not what you want. I assume you added the 'arrayLiteral' argument label because the compiler told you so, however this compiles :
let foo = Set(["string1", "string2"])
and it returns a Set<String>.
The problem is that I couldn't find a way to create a Set of class types. I've asked on Apple's devforums : https://devforums.apple.com/thread/271316 but unless I'm missing something obvious, this looks like an API bug.

How can I create an Action<T> in F#?

I am using the Moq framework for unit testing and would like to be able to pass in Action for logging void methods.
let log = new Mock<ILog>()
let quot = <# fun (mock:ILog) -> mock.Info(It.IsAny<string>) #>
let expr = (quot.ToLinqExpression() :?> Expression<Action<ILog>>)
log.Verify(expr)
This code fails with the following error:
System.InvalidCastException : Unable to cast object of type
'System.Linq.Expressions.MethodCallExpressionN' to type
'System.Linq.Expressions.Expression1[System.Action1[log4net.ILog]]'.
I can print the type out using
printfn "%s" (quot.Type.ToString())
which outputs
Microsoft.FSharp.Core.FSharpFunc`2[log4net.ILog,Microsoft.FSharp.Core.Unit]
So, how can I create an Action?
LINQ Expressions are fully supported in F# 3, so you can now pass an Action to Moq as a lambda expression:
let mock = Mock<ILog>()
mock.Verify(fun (log:ILog) -> log.Info(It.IsAny<string>()))
Try:
let quot = <# new Action<_>(fun (mock:ILog) -> mock.Info(It.IsAny<string>)) #>

TRttiMethod::Invoke use

I would like to know how to use the Invoke method of the TRttiMethod class in C++Builder 2010.
This is my code
Tpp *instance=new Tpp(this);
TValue *args;
TRttiContext * ctx=new TRttiContext();
TRttiType * t = ctx->GetType(FindClass(instance->ClassName()));
TRttiMethod *m=t->GetMethod("Show");
m->Invoke(instance,args,0);
Show has no arguments and it is __published. When I execute I get a EInvocationError with message 'Parameter count mismatch'.
Can someone demonstrate the use of Invoke? Both no arguments and with arguments in the called method.
Thanks
Josep
You get the error because you are telling Invoke() that you are passing in 1 method parameter (even though you really are not, but that is a separate bug in your code). Invoke() takes an OPENARRAY of TValue values as input. Despite its name, the Args_Size parameter is not the NUMBER of parameters being passed in, but rather is the INDEX of the last parameter in the array. So, to pass 0 method parameters to Show() via Invoke(), set the Args parameter to NULL and the Args_Size parameter to -1 instead of 0, ie:
Tpp *instance = new Tpp(this);
TRttiContext *ctx = new TRttiContext;
TRttiType *t = ctx->GetType(instance->ClassType());
TRttiMethod *m = t->GetMethod("Show");
m->Invoke(instance, NULL, -1);
delete ctx;
Now, once you fix that, you will notice Invoke() start to raise an EInsufficientRtti exception instead. That happens when Runtime Packages are enabled. Unfortunately, disabling Runtime Packages will cause TRttiContext::GetType() to raise an EAccessViolation in TRttiPool::GetPackageFor() because of a known linker bug under C++:
QC #76875, RAID #272782: InitContext.PackageTypeInfo shouldn't be 0 in a C++ module:
Which causes these bugs:
QC #76672, RAID #272419: Rtti.pas is unusable in a C++ application
QC #76877, RAID #272767: AV in TRttiContext::GetType() when Runtime Packages are disabled
So you are in a catch-22 situation. The new RTTI system is not ready for production work in C++ yet. You will have to use Delphi instead for the time being.

Resources