I'm building a GatewayFilter, but I'm having problems handling cases where I don't have data. Here is a sample of the GatewayFilterFactory<>:
return (exchange, chain) -> getDataFromRedis()
.flatMap(redisData -> {
ServerHttpRequest request = exchange.getRequest().mutate()
.header("header", redisData).build();
return chain.filter(exchange.mutate().request(request).build());
});
Here is the getDataFromRedis method:
Mono<String> getDataFromRedis() {
return redis.get("key");
}
It returns a Mono with a String value, or empty if it wasn't found.
The above example works as expected, but when the data is redis is not found, and an empty Mono is returned, then I need it to return a redirect. So this is my attempt:
return (exchange, chain) -> getDataFromRedis()
.flatMap(redisData -> {
ServerHttpRequest request = exchange.getRequest().mutate()
.header("header", redisData).build();
return chain.filter(exchange.mutate().request(request).build());
})
.switchIfEmpty(Mono.defer(() -> {
exchange.getResponse().setStatusCode(HttpStatus.FOUND);
exchange.getResponse().getHeaders().add(HttpHeaders.LOCATION, "some other url");
return exchange.getResponse().setComplete();
}));
The deferred mono in switchIfEmpty is always invoked, irrespective of whether there is data in redis or not.
To summarise, I need the filter to add a header value it gets from Redis, but redirect if there is no data available.
Related
I'm lost trying to understand how Dart shelf executes the middleware and handlers. From all the documentation I have read (and briefing it up) if you write a Middleware that returns null, then the execution goes down the pipeline.
Otherwise if the middleware returns a Response, then the execution down the pipeline is stopped, and the Response is returned to the caller.
I have a server with a simple pipeline like this:
var handler = const shelf.Pipeline()
.addMiddleware(shelf.logRequests())
//.addMiddleware(options)
.addMiddleware(auth)
.addHandler(Router.handle);
The auth middleware checks 3 cases: Register, Login and Verify.
Register -> Creates new user and returns Response.ok(token), or if nor possible Response.InternalServerError
Login -> Refreshes the token and returns Response.ok(token), or if not correct Response(401)
Verify -> Returns null when ok(should continue down the pipeline), or Response(403, forbidden)
The problem is, that I cannot stop the execution of the middlewares. If I make a successful login, still the program goes down the pipeline and calls the Router. Which of course doesn't have the path for register and returns 404 as it is expected to do.
According to shelf documentation, it is supposed to stop when a middleware returns a response. What the hell am I doing wrong?
This is the code of the auth Middleware for reference:
abstract class AuthProvider {
static JsonDecoder _decoder = const JsonDecoder();
static FutureOr<Response> handle(Request request) async {
print('Entering auth middleware');
if(request.url.toString() == 'login'){
print('into login from auth');
AuthProvider.auth(request);
}
else if(request.url.toString() == 'register'){
print('Into register from auth');
RegisterController.handle(request);
}
else {
print('Into verify from auth');
AuthProvider.verify(request);
}
}
static FutureOr<Response> auth(Request request) async {
print('Entering auth');
String sql;
var query = ExecQuery();
try {
dynamic data = jsonDecode(await request.readAsString()) as Map<String, dynamic>;
final user = data['email'].toString();
final hash = Hash.create(data['password'].toString());
sql =
'''SELECT COUNT(*) FROM public.user WHERE (email = '${user}' AND password = '${hash}')''';
await query.countSql(sql);
if (query.result.status && query.result.opResult[0][0] == 1) {
JwtClaim claim = JwtClaim(
subject: user,
issuer: 'Me',
audience: ['users'],
);
final token = issueJwtHS256(claim, config.secret);
sql = '''UPDATE public.user SET token = '${token}'
WHERE (email = '${user}' AND password = '${hash}')''';
await query.rawQuery(sql);
return Response.ok(token);
}
else{throw Exception();}
} catch (e) {
return Response(401, body: 'Incorrect username/password');
}
}
static FutureOr<Response> verify(Request request) async {
print('Entering verify');
try {
final token = request.headers['Authorization'].replaceAll('Bearer ', '');
print('Received token: ${token}');
final claim = verifyJwtHS256Signature(token, config.secret);
print('got the claim');
claim.validate(issuer: 'ACME Widgets Corp',
audience: 'homacenter');
print ('returning null in middleware');
return null;
} catch(e) {
print(e.toString());
return Response.forbidden('Authorization rejected');
}
}
}
I reply myself... after losing days in this, a return was missing, that made the pipeline keep going. Issue closed.
abstract class AuthProvider {
static JsonDecoder _decoder = const JsonDecoder();
static FutureOr<Response> handle(Request request) async {
if(request.url.toString() == 'login'){
return AuthProvider.auth(request);
}
else if(request.url.toString() == 'register'){
return RegisterController.handle(request);
}
else {
return AuthProvider.verify(request);
}
}
I have a script groovy, this script for live fetching of docker image,
I want to add the authentication function with the private repository, but I am not familiar with groovy, who can help me, thanks
import groovy.json.JsonSlurper
// Set the URL we want to read from, it is MySQL from official Library for this example, limited to 20 results only.
docker_image_tags_url = "https://registry.adx.abc/v2/mysql/tags/list"
try {
// Set requirements for the HTTP GET request, you can add Content-Type headers and so on...
def http_client = new URL(docker_image_tags_url).openConnection() as HttpURLConnection
http_client.setRequestMethod('GET')
// Run the HTTP request
http_client.connect()
// Prepare a variable where we save parsed JSON as a HashMap, it's good for our use case, as we just need the 'name' of each tag.
def dockerhub_response = [:]
// Check if we got HTTP 200, otherwise exit
if (http_client.responseCode == 200) {
dockerhub_response = new JsonSlurper().parseText(http_client.inputStream.getText('UTF-8'))
} else {
println("HTTP response error")
System.exit(0)
}
// Prepare a List to collect the tag names into
def image_tag_list = []
// Iterate the HashMap of all Tags and grab only their "names" into our List
dockerhub_response.results.each { tag_metadata ->
image_tag_list.add(tag_metadata.name)
}
// The returned value MUST be a Groovy type of List or a related type (inherited from List)
// It is necessary for the Active Choice plugin to display results in a combo-box
return image_tag_list.sort()
} catch (Exception e) {
// handle exceptions like timeout, connection errors, etc.
println(e)
}
The problem has been resolved, thank you everyone for your help
// Import the JsonSlurper class to parse Dockerhub API response
import groovy.json.JsonSlurper
// Set the URL we want to read from, it is MySQL from official Library for this example, limited to 20 results only.
docker_image_tags_url = "https://registry.adx.vn/v2/form-be/tags/list"
try {
// Set requirements for the HTTP GET request, you can add Content-Type headers and so on...
def http_client = new URL(docker_image_tags_url).openConnection() as HttpURLConnection
http_client.setRequestMethod('GET')
String userCredentials = "your_user:your_passwd";
String basicAuth = "Basic " + new String(Base64.getEncoder().encode(userCredentials.getBytes()));
http_client.setRequestProperty ("Authorization", basicAuth);
// Run the HTTP request
http_client.connect()
// Prepare a variable where we save parsed JSON as a HashMap, it's good for our use case, as we just need the 'name' of each tag.
def dockerhub_response = [:]
// Check if we got HTTP 200, otherwise exit
if (http_client.responseCode == 200) {
dockerhub_response = new JsonSlurper().parseText(http_client.inputStream.getText('UTF-8'))
} else {
println("HTTP response error")
System.exit(0)
}
// Prepare a List to collect the tag names into
def image_tag_list = []
// Iterate the HashMap of all Tags and grab only their "names" into our List
dockerhub_response.tags.each { tag_metadata ->
image_tag_list.add(tag_metadata)
}
// The returned value MUST be a Groovy type of List or a related type (inherited from List)
// It is necessary for the Active Choice plugin to display results in a combo-box
return image_tag_list.sort()
} catch (Exception e) {
// handle exceptions like timeout, connection errors, etc.
println(e)
}
here is the result
I am new to JavaScript frameworks and currently trying to setup a falcor router calling an external api (for now consider it as an express api app + mango db, hosted at 3000 port).
Now, I am able to use the request package (commented out lines) and successfully call the Express Api app (which returns obj.rating = 4). But I am unable to send this value from the falcor router instead of the hard-coded value "5".
Below is the falcor-router's server.js code:
app.use('/rating.json', falcorExpress.dataSourceRoute(function (req, res) {
return new Router([
{
route: "rating",
get: function() {
var obj;
// request('http://localhost:3000/rating/101', function (error, response, body) {
// obj = JSON.parse(body);
// console.log('rating:', obj.rating); // obj.rating = 4
// });
return {path:["rating"], value:"5"};
}
}
]);
}));
The below is the code for index.html:
<script>
function showRating() {
var model = new falcor.Model({source: new falcor.HttpDataSource('http://localhost/rating.json') });
model.
get("rating").
then(function(response) {
document.getElementById('filmRating').innerText = JSON.stringify(response.json,null, 4);
});
}
</script>
I also tried to look at the global variable declaration, synchronize http request calls, promises, then statements etc. But nothing seemed to work, clearly I am missing out something here - not sure what.
The router's get handler expects the return value to be a promise or an observable that resolves to a pathValue. To get your request against the db to work, simply return a promise that resolves to a pathValue, e.g.
return new Router([
{
route: "rating",
get: function() {
return request('http://localhost:3000/rating/101', function (error, response, body) {
return { path: ["rating", value: JSON.parse(body).rating };
});
}
}
]);
tamGetir(yno){
let yazilan:any;
let body={
uyeno:this.uye.uyeno,
eposta: this.uye.eposta,
sifre: this.uye.sifre,
gunlukno: this.defterno,
yazino: yno
}
this.http.post('http://www.gibigo.com/sayfalar/ion_android_gungetir2.php',JSON.stringify(body))
.map(res=>res.json())
.subscribe(data=>{
console.log(data.yazi);
yazilan=data.yazi;
});
return yazilan;
}
"data.yazi" looks correct in console, but return operation does not work. Return is undifinied. How can i return it correct.
The http function returns an Observable. This is asynchrounous. When you use subscribe, the http request is fired and an observable is returned. The data is received on response.
yazilan=data.yazi; is happening after the return statement.
You should use a class variable to simply save the data within the subscription.
If your method is in a provider, return the http call with map and subscribe in your component
tamGetir(yno){
let yazilan:any;
let body={
uyeno:this.uye.uyeno,
eposta: this.uye.eposta,
sifre: this.uye.sifre,
gunlukno: this.defterno,
yazino: yno
}
return this.http.post('http://www.gibigo.com/sayfalar/ion_android_gungetir2.php',JSON.stringify(body))
.map(res=>res.json())
In your component:
yazi:any;//class variable
callHttpFunction(){
this.provider.tamGetir(yno)
.subscribe(data=>{//call the subsribe
console.log(data);
this.data_variable =data.yazi;
})
}
I am able to do transactions in Hyperledger (fabric implementation). I want to see all the transactions and its payload details initiated by a user by passing the user's key.
for example:
A transfers 10 units to B
A transfers 5 units to C
D transfers 8 units to A
When I pass A's key then fabric must provide me all the transactions of A.
Is there any way? Or which fabric API function call should I use?
/chain/blocks/{Block} endpoint carries ordered list of transactions in a specified block.
Use /chain endpoint to get the height (number of blocks) of your chain, and then retrieve transactions from each block using /chain/blocks/{Block} REST endpoint.
You can develop the proper indexing and query function in your chaincode.
Meaning for each transaction you store its details in the internal key/value store (stub.PutState) with the user as key and return all the transactions associated to a user in your query (stub.GetState).
The best and simplest way is to use the shim package function
GetHistoryForKey(key string)
As the documentation says:
GetHistoryForKey function can be invoked by a chaincode to return a history of key values across time.
GetHistoryForKey is intended to be used for read-only queries.
IF anyone need Java SDk and go chaincode combination. There you go
answered here similar question
Java code
public List<HistoryDao> getUFOHistory(String key) throws Exception {
String[] args = { key };
Logger.getLogger(QueryChaincode.class.getName()).log(Level.INFO, "UFO communication history - " + args[0]);
Collection<ProposalResponse> responses1Query = ucc.getChannelClient().queryByChainCode("skynetchaincode", "getHistoryForUFO", args);
String stringResponse = null;
ArrayList<HistoryDao> newArrayList = new ArrayList<>();
for (ProposalResponse pres : responses1Query) {
stringResponse = new String(pres.getChaincodeActionResponsePayload());
Logger.getLogger(QueryChaincode.class.getName()).log(Level.INFO, stringResponse);
newArrayList = gson.fromJson(stringResponse, new TypeToken<ArrayList<HistoryDao>>() {
}.getType());
}
if (null == stringResponse)
stringResponse = "Not able to find any ufo communication history";
return newArrayList;
}
and you go chancode implemetation is as follows
Go code
func (t *SmartContract) getHistoryForUFO(APIstub shim.ChaincodeStubInterface, args []string) sc.Response {
if len(args) < 1 {
return shim.Error("Incorrect number of arguments. Expecting 1")
}
ufoId := args[0]
resultsIterator, err := APIstub.GetHistoryForKey(ufoId)
if err != nil {
return shim.Error(err.Error())
}
defer resultsIterator.Close()
var buffer bytes.Buffer
buffer.WriteString("[")
bArrayMemberAlreadyWritten := false
for resultsIterator.HasNext() {
response, err := resultsIterator.Next()
if err != nil {
return shim.Error(err.Error())
}
// Add a comma before array members, suppress it for the first array member
if bArrayMemberAlreadyWritten == true {
buffer.WriteString(",")
}
buffer.WriteString("{\"TxId\":")
buffer.WriteString("\"")
buffer.WriteString(response.TxId)
buffer.WriteString("\"")
buffer.WriteString(", \"Value\":")
// if it was a delete operation on given key, then we need to set the
//corresponding value null. Else, we will write the response.Value
//as-is (as the Value itself a JSON)
if response.IsDelete {
buffer.WriteString("null")
} else {
buffer.WriteString(string(response.Value))
}
buffer.WriteString(", \"Timestamp\":")
buffer.WriteString("\"")
buffer.WriteString(time.Unix(response.Timestamp.Seconds, int64(response.Timestamp.Nanos)).String())
buffer.WriteString("\"")
buffer.WriteString(", \"IsDelete\":")
buffer.WriteString("\"")
buffer.WriteString(strconv.FormatBool(response.IsDelete))
buffer.WriteString("\"")
buffer.WriteString("}")
bArrayMemberAlreadyWritten = true
}
buffer.WriteString("]")
fmt.Printf("- History returning:\n%s\n", buffer.String())
return shim.Success(buffer.Bytes())
}
Let me know if you question.
If you are using composer-client, you can simply use the Historian command.
var historian = await businessNetworkConnection.getHistorian();
historian.getAll().then(historianRecords => console.log(historianRecords));