How to get the value of another function synchronously - kotlin

I am using the ktor websocket module
When I send data to the client, how do I get the data back from the client after this send?
val result = serverSession.send(json)
// result
Just like this
It is actually the Unit type
But I want to get the String

There are great examples on official site of Ktor.
If you are server-side, check this link (https://ktor.io/docs/websocket.html#handle-single-session) and the below example.
webSocket("/echo") {
send("Please enter your name")
for (frame in incoming) {
when (frame) {
is Frame.Text -> {
val receivedText = frame.readText()
if (receivedText.equals("bye", ignoreCase = true)) {
close(CloseReason(CloseReason.Codes.NORMAL, "Client said BYE"))
} else {
send(Frame.Text("Hi, $receivedText!"))
}
}
}
}
}
If you are client-side, check this link (https://ktor.io/docs/websocket-client.html#example) and the below example.
client.webSocket(method = HttpMethod.Get, host = "127.0.0.1", port = 8080, path = "/echo") {
while(true) {
val othersMessage = incoming.receive() as? Frame.Text
println(othersMessage?.readText())
val myMessage = Scanner(System.`in`).next()
if(myMessage != null) {
send(myMessage)
}
}
}

Related

Using MQTT ManagedClient with ASP NET API, how to?

I'm currently working on a project that has to rely heavily on MQTT - one of the parts that needs to utilize MQTT is a ASP Net API, but I'm having difficulties receiving messages.
Here is my MQTTHandler:
public MQTTHandler()
{
_mqttUrl = Properties.Resources.mqttURL ?? "";
_mqttPort = Properties.Resources.mqttPort ?? "";
_mqttUsername = Properties.Resources.mqttUsername ?? "";
_mqttPassword = Properties.Resources.mqttUsername ?? "";
_mqttFactory = new MqttFactory();
_tls = false;
}
public async Task<IManagedMqttClient> ConnectClientAsync()
{
var clientID = Guid.NewGuid().ToString();
var messageBuilder = new MqttClientOptionsBuilder()
.WithClientId(clientID)
.WithCredentials(_mqttUsername, _mqttPassword)
.WithTcpServer(_mqttUrl, Convert.ToInt32(_mqttPort));
var options = _tls ? messageBuilder.WithTls().Build() : messageBuilder.Build();
var managedOptions = new ManagedMqttClientOptionsBuilder()
.WithAutoReconnectDelay(TimeSpan.FromSeconds(5))
.WithClientOptions(options)
.Build();
_mqttClient = new MqttFactory().CreateManagedMqttClient();
await _mqttClient.StartAsync(managedOptions);
Console.WriteLine("Klient startet");
return _mqttClient;
}
public async Task PublishAsync(string topic, string payload, bool retainFlag = true, int qos = 1)
{
await _mqttClient.EnqueueAsync(new MqttApplicationMessageBuilder()
.WithTopic(topic)
.WithPayload(payload)
.WithQualityOfServiceLevel((MQTTnet.Protocol.MqttQualityOfServiceLevel)qos)
.WithRetainFlag(retainFlag)
.Build());
Console.WriteLine("Besked published");
}
public async Task SubscribeAsync(string topic, int qos = 1)
{
var topicFilters = new List<MQTTnet.Packets.MqttTopicFilter>
{
new MqttTopicFilterBuilder()
.WithTopic(topic)
.WithQualityOfServiceLevel((MQTTnet.Protocol.MqttQualityOfServiceLevel)(qos))
.Build()
};
await _mqttClient.SubscribeAsync(topicFilters);
}
public Status GetSystemStatus(MqttApplicationMessageReceivedEventArgs e)
{
try
{
var json = Encoding.UTF8.GetString(e.ApplicationMessage.Payload);
var status = JsonSerializer.Deserialize<Status>(json);
if (status != null)
{
return status;
}
else
{
return null;
}
}
catch (Exception)
{
throw;
}
}
The above has been tested with a console app and works as it should.
The reason I need MQTT in the APi is that a POST method has to act on the value of a topic;
In particular I need to check a systems status before allowing the post;
[HttpPost]
public async Task<ActionResult<Order>> PostOrder(Order order)
{
if (_lastStatus != null)
{
if (_lastStatus.OpStatus)
{
return StatusCode(400, "System is busy!");
}
else
{
var response = await _orderManager.AddOrder(order);
return StatusCode(response.StatusCode, response.Message);
}
}
return StatusCode(400, "Something went wrong");
}
So I will need to set up a subscriber for this controller, and set the value of _lastStatus on received messages:
private readonly MQTTHandler _mqttHandler;
private IManagedMqttClient _mqttClient;
private Status _lastStatus;
public OrdersController(OrderManager orderManager)
{
_orderManager = orderManager;
_mqttHandler = new MQTTHandler();
_mqttClient = _mqttHandler.ConnectClientAsync().Result;
_mqttHandler.SubscribeAsync("JSON/Status");
_mqttClient.ApplicationMessageReceivedAsync += e =>
{
_lastStatus = _mqttHandler.GetSystemStatus(e);
return Task.CompletedTask;
};
}
However, it's behaving a little odd and I'm not experienced enough to know why.
The first time I make a POST request, _lastStatus is null - every following POST request seem to have the last retained message.
I'm guessing that I am struggling due to stuff being asynchronous, but not sure, and every attempt I've attempted to make it synchronous have failed.
Anyone have a clue about what I'm doing wrong?

Unable to access DynamoDb Locally from Kotlin

First I want to say I am pretty new to Kotlin and DynamoDB. I am writing a sample program in Kotlin to play with DynamoDb. I am following the steps in this link: https://docs.aws.amazon.com/sdk-for-kotlin/latest/developer-guide/examples-dynamodb-tables.html
First I instantiate a client object for making requests to DynamoDB
val dynamoDbClient = DynamoDbClient { region = "us-east-1" }
Then I run the code below to create a new table.
suspend fun createNewTable(ddb: DynamoDbClient, newTableName: String, key: String): String {
val attDef = AttributeDefinition {
attributeName = key
attributeType = ScalarAttributeType.S
}
val keySchemaVal = KeySchemaElement {
attributeName = key
keyType = KeyType.Hash
}
val provisionedVal = ProvisionedThroughput {
readCapacityUnits = 10
writeCapacityUnits = 10
}
val request = CreateTableRequest {
attributeDefinitions = listOf(attDef)
keySchema = listOf(keySchemaVal)
provisionedThroughput = provisionedVal
tableName = newTableName
}
try {
val response = ddb.createTable(request)
val tableActive = false
// Wait until the table is in Active state.
while (!tableActive) {
val tableStatus = checkTableStatus(ddb, newTableName)
if (tableStatus.equals("ACTIVE"))
break
delay(500)
}
return response.tableDescription?.tableArn.toString()
} catch (e: DynamoDbException) {
println("ERROR (DynamoDbException): " + e.message)
} catch (e: UnknownServiceErrorException) {
println("ERROR (UnknownServiceErrorException): " + e.message)
} finally {
ddb.close()
}
return ""
}
I can see the table created on my AWS account. However I want to modify my DynamoDbClient to execute the table creation on a local instance of the DynamoDB. I followed the instructions from AWS pages and I installed DynamoDB locally.
Here is how I am running it locally:
c:\code\dynamodb_local_latest>java -Djava.library.path=./DynamoDBLocal_lib -jar DynamoDBLocal.jar -sharedDb
Initializing DynamoDB Local with the following configuration:
Port: 8000
InMemory: false
DbPath: null
SharedDb: true
shouldDelayTransientStatuses: false
CorsParams: *
I am able to access the local DynamoDB instance from the aws cli tool.
In order to try accessing the local instance of DynamoDB from the Kotlin code, I changed DynamoDbClient from this:
val dynamoDbClient = DynamoDbClient { region = "us-east-1" }
to this:
val endpoint = aws.sdk.kotlin.runtime.endpoint.Endpoint( "localhost",
"http",
port=8000,
false,
null,
"us-west-1")
val myEndpointResolver = StaticEndpointResolver(endpoint)
val dynamoDbClient = DynamoDbClient {endpointResolver = myEndpointResolver; region ="us-west-1" }
However I get the following error:
Exception in thread "DefaultDispatcher-worker-1" software.amazon.awssdk.crt.http.HttpException: socket connection refused.
at software.amazon.awssdk.crt.http.HttpClientConnection.onConnectionAcquired(HttpClientConnection.java:85)
What is the proper way to resolve that?
Thanks!
You can specify the EndPointResolver for the DynamoDbClient with the address of your DynamoDb local instance.
For example:
class LocalHostDynamoDb: AwsEndpointResolver {
override suspend fun resolve(service: String, region: String): AwsEndpoint
= AwsEndpoint("http://localhost:8000")
}
class MyClient {
...
val dynamoDbClient = DynamoDbClient {
region = awsRegion
endpointResolver = LocalHostDynamoDb()
}
...

Want to create a circuit breaker using vert.x for rabbit MQ

I want to implement circuit breaker using vert.x for rabbit mq. if rabbit mq is down then circuit is open based on the configuration.
I did separate POC for vert.x circuit breaker and also able to connect with Rabbit MQ client . using vert.x .
Now, I want to build circuit breaker if circuit is open then client will not to push messages in queue , and keep in data base, once circuit is closed then it will start pushing db messages in mq. Please help.
I've use below links for create working poc.
https://vertx.io/docs/vertx-circuit-breaker/java/
https://vertx.io/docs/vertx-rabbitmq-client/java/
Snippet Used for Circuit Breaker
CircuitBreakerOptions options = new CircuitBreakerOptions()
.setMaxFailures(0)
.setTimeout(5000)
.setMaxRetries(3)
.setFallbackOnFailure(true);
CircuitBreaker breaker =
CircuitBreaker.create("my-circuit-breaker", vertx, options)
.openHandler(v -> {
System.out.println("Circuit opened");
}).closeHandler(v -> {
System.out.println("Circuit closed");
}).retryPolicy(retryCount -> retryCount * 100L);
breaker.executeWithFallback(promise -> {
vertx.createHttpClient().getNow(8080, "localhost", "/", response -> {
if (response.statusCode() != 200) {
promise.fail("HTTP error");
} else {
response.exceptionHandler(promise::fail).bodyHandler(buffer -> {
promise.complete(buffer.toString());
});
}
});
}, v -> {
// Executed when the circuit is opened
return "Hello (fallback)";
}, ar -> {
// Do something with the result
System.out.println("Result: " + ar.result());
});
}
Snippet Used for RAbbit MQ Client
public static void main(String[] args) {
Vertx vertx = Vertx.vertx();
RabbitMQOptions config = new RabbitMQOptions();
// Each parameter is optional
// The default parameter with be used if the parameter is not set
config.setUser("guest");
config.setPassword("guest");
config.setHost("localhost");
config.setPort(5672);
// config.setVirtualHost("vhost1");
// config.setConnectionTimeout(6000); // in milliseconds
config.setRequestedHeartbeat(60); // in seconds
// config.setHandshakeTimeout(6000); // in milliseconds
// config.setRequestedChannelMax(5);
// config.setNetworkRecoveryInterval(500); // in milliseconds
// config.setAutomaticRecoveryEnabled(true);
// vertx.
RabbitMQClient client = RabbitMQClient.create(vertx, config);
CircuitBreakerOptions options = new CircuitBreakerOptions().setMaxFailures(0).setTimeout(5000).setMaxRetries(0)
.setFallbackOnFailure(true);
CircuitBreaker breaker = CircuitBreaker.create("my-circuit-breaker", vertx, options).openHandler(v -> {
System.out.println("Circuit opened");
}).closeHandler(v -> {
System.out.println("Circuit closed");
}).retryPolicy(retryCount -> retryCount * 100L);
breaker.executeWithFallback(promise -> {
vertx.createHttpClient().getNow(8080, "localhost", "/", response -> {
if (response.statusCode() != 200) {
promise.fail("HTTP error");
} else {
response.exceptionHandler(promise::fail).bodyHandler(buffer -> {
promise.complete(buffer.toString());
});
}
});
}, v -> {
// Executed when the circuit is opened
return "Hello (fallback)";
}, ar -> {
// Do something with the result
System.out.println("Result: " + ar.result());
});
client.start(rh -> {
if (rh.failed()) {
System.out.println("failed");
} else {
for (int i = 0; i > 5; i++) {
System.out.println(rh.succeeded());
System.out.println("client : " + client.isConnected());
breaker.executeWithFallback(promise -> {
if(!client.isConnected()) {
promise.fail("MQ client is not connected");
}
},v -> {
// Executed when the circuit is opened
return "Hello (fallback)";
}, ar -> {
// Do something with the result
System.out.println("Result: " + ar.result());
});
/* RabbitMQClient client2 = RabbitMQClient.create(vertx); */
JsonObject message = new JsonObject().put("body", "Hello RabbitMQ, from Vert.x !");
client.basicPublish("eventExchange", "order.created", message, pubResult -> {
if (pubResult.succeeded()) {
System.out.println("Message published !");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} else {
pubResult.cause().printStackTrace();
}
});
}
}
});
}
Although its working but, circuit open in case rabbit mq down . But its not looks a standard way of ding it with vert.x .
CAn you please suggest of give input how i can implement it.

Smack: SSL/TLS required by server but disabled in client

I am developing one to one chat , but i am facing the issue SSL/TLS required by server but disabled in client ,don't know what i am doing wrong , please help me out to figure out the mistake
My Service Class:
class ChatService:Service() {
var text = ""
var chat:Chat?=null
companion object {
private val DOMAIN = "localhost"
private val USERNAME = "admin#localhost"
private val PASSWORD = "localhost"
var cm: ConnectivityManager? = null
var xmpp: MyXMPP? = null
var ServerchatCreated = false
fun isNetworkConnected(): Boolean {
return cm!!.getActiveNetworkInfo() != null
}
}
override fun onCreate() {
super.onCreate()
cm= getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager?
xmpp = MyXMPP.getInstance(this, DOMAIN, USERNAME, PASSWORD);
xmpp!!.connect("onCreate");
}
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
return START_NOT_STICKY
}
override fun onBind(intent: Intent?): IBinder? {
return LocalBinder<ChatService>(this)
}
override fun onDestroy() {
super.onDestroy()
xmpp!!.disconnect();
}
}
My XMPP Class For the connection:
companion object {
fun getInstance(context: ChatService, server: String, user: String, pass: String): MyXMPP {
if (instance == null) {
instance = MyXMPP(context, server, user, pass)
instanceCreated = true
}
return instance!!
}
}
constructor(context: ChatService, serverAdress: String, logiUser: String, passwordser: String) {
this.serverAddress = serverAdress
this.loginUser = logiUser
this.passwordUser = passwordser
this.context = context
initialiseConnection()
}
private fun initialiseConnection() {
val serviceName = JidCreate.domainBareFrom("localhost")
val config = XMPPTCPConnectionConfiguration.builder()
config.setSecurityMode(ConnectionConfiguration.SecurityMode.disabled)
config.setServiceName(serviceName)
config.setHostAddress(InetAddress.getByName("192.168.0.101"))//my ip address
config.setPort(5222)
config.setXmppDomain(serviceName)
config.setDebuggerEnabled(true)
//System.setProperty("smack.debugEnabled", "true")
XMPPTCPConnection.setUseStreamManagementResumptiodDefault(true)
XMPPTCPConnection.setUseStreamManagementDefault(true)
connection = XMPPTCPConnection(config.build())
val connectionListener = XMPPConnectionListener()
connection!!.addConnectionListener(connectionListener)
}
Inner class to MyXMPP class:
inner class XMPPConnectionListener : ConnectionListener {
override fun connected(connection: XMPPConnection) {
Log.d("xmpp", "Connected!")
connected = true
if (!connection.isAuthenticated) {
login()
}
}
override fun connectionClosed() {
if (isToasted)
Handler(Looper.getMainLooper()).post(Runnable {
// TODO Auto-generated method stub
Toast.makeText(
context, "ConnectionCLosed!",
Toast.LENGTH_SHORT
).show()
})
Log.d("xmpp", "ConnectionCLosed!")
connected = false
chat_created = false
loggedin = false
}
override fun connectionClosedOnError(arg0: Exception) {
if (isToasted)
Handler(Looper.getMainLooper()).post(Runnable {
Toast.makeText(
context, "ConnectionClosedOn Error!!",
Toast.LENGTH_SHORT
).show()
})
Log.d("xmpp", "ConnectionClosedOn Error!")
connected = false
chat_created = false
loggedin = false
}
Login to ejabber server :
fun login() {
try {
connection?.login(loginUser, passwordUser)
Log.i("LOGIN", "Yey! We're connected to the Xmpp server!")
} catch (e: XMPPException) {
e.printStackTrace()
} catch (e: SmackException) {
e.printStackTrace()
} catch (e: IOException) {
e.printStackTrace()
} catch (e: Exception) {
}
}
Logcat :
D/SMACK: RECV (0): <?xml version='1.0'?><stream:stream id='1777473137180053616' version='1.0' xml:lang='en' xmlns:stream='http://etherx.jabber.org/streams' from='localhost' xmlns='jabber:client'>
2019-04-29 13:25:40.247 30893-30976/shop.com.letsshop D/SMACK: RECV (0): <stream:features><starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'><required/></starttls></stream:features>
2019-04-29 13:25:40.249 30893-30974/shop.com.letsshop E/(onCreate): SMACKException: SSL/TLS required by server but disabled in client
2019-04-29 13:25:40.251 30893-30976/shop.com.letsshop W/AbstractXMPPConnection: Connection XMPPTCPConnection[not-authenticated] (0) closed with error
org.jivesoftware.smack.SmackException$SecurityRequiredByServerException: SSL/TLS required by server but disabled in client
at org.jivesoftware.smack.tcp.XMPPTCPConnection.afterFeaturesReceived(XMPPTCPConnection.java:928)
at org.jivesoftware.smack.AbstractXMPPConnection.parseFeatures(AbstractXMPPConnection.java:1446)
at org.jivesoftware.smack.tcp.XMPPTCPConnection.access$1100(XMPPTCPConnection.java:149)
at org.jivesoftware.smack.tcp.XMPPTCPConnection$PacketReader.parsePackets(XMPPTCPConnection.java:1048)
at org.jivesoftware.smack.tcp.XMPPTCPConnection$PacketReader.access$300(XMPPTCPConnection.java:980)
at org.jivesoftware.smack.tcp.XMPPTCPConnection$PacketReader$1.run(XMPPTCPConnection.java:996)
at java.lang.Thread.run(Thread.java:764)
2019-04-29 13:25:40.252 30893-30976/shop.com.letsshop D/xmpp: ConnectionClosedOn Error!
After lot's of struggle i found the solution :)
MyXmpp Class :
val serviceName = JidCreate.domainBareFrom("localhost")// if user is register as admin#localhost ,you should have to take only string after "#" i.e localhost
val config = XMPPTCPConnectionConfiguration.builder()
config.setSecurityMode(ConnectionConfiguration.SecurityMode.required);
config.setXmppDomain(serviceName);
config.setHostAddress( InetAddress.getByName("192.168.0.101"))// your server ip address or for local host ,pc ip address
config.setPort(5222)
config.setDebuggerEnabled(true)
val sslContext = getSSLContext()// setting ssl
config.setCustomSSLContext(sslContext)
SASLAuthentication.blacklistSASLMechanism("SCRAM-SHA-1")
SASLAuthentication.blacklistSASLMechanism("DIGEST-MD5")
SASLAuthentication.unBlacklistSASLMechanism("PLAIN")
XMPPTCPConnection.setUseStreamManagementResumptiodDefault(true)
XMPPTCPConnection.setUseStreamManagementDefault(true)
connection = XMPPTCPConnection(config.build())
connection?.login("admin", "localhost")//ejabber server login id .if you have admin#localhost then take only admin as a username . password i am having as localhost.
Enabling the SSL :
#Throws(IOException::class,
CertificateException::class, NoSuchAlgorithmException::class, KeyStoreException::class, KeyManagementException::class)
private fun getSSLContext():SSLContext{
var cf: CertificateFactory? =null
try {
cf = CertificateFactory.getInstance("X.509");
} catch (e:CertificateException) {
Log.d("ca", "ca=" + e.message);
}
var input = context.getResources().openRawResource(R.raw.my_keystore); // R.raw.chain is CA Root Certificate added in RAW resources folder
var caInput = BufferedInputStream(input);
var ca:Certificate?=null
try {
ca = cf!!.generateCertificate(caInput)
// Log.d("ca", "ca=" + ((X509Certificate) ca).getSubjectDN())
}
catch (e:Exception){
Log.e("ca", e.message);
}
finally {
caInput.close();
}
// Create a KeyStore containing our trusted CAs
var keyStoreType = KeyStore.getDefaultType();
var keyStore = KeyStore.getInstance(keyStoreType);
keyStore.load(null, null);
keyStore.setCertificateEntry("ca", ca);
// Create a TrustManager that trusts the CAs in our KeyStore
var tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
var tmf = TrustManagerFactory.getInstance(tmfAlgorithm);
tmf.init(keyStore);
// Create an SSLContext that uses our TrustManager
var sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, tmf.getTrustManagers(), null);
return sslContext;
}
Here i got stuck : How to find the my_keystore . Then I found in server.pem file in ejabbered there you find private key that key i have to paste in the client side(Android Studio->res->raw(folder)->my_keystore(make a empty file like this)) i.e in my_keystore file .Here is the full path to reach server.pem . /opt/ejabberd/conf
in your initialiseConnection() method
change
config.setSecurityMode(ConnectionConfiguration.SecurityMode.disabled)
to
config.setSecurityMode(ConnectionConfiguration.SecurityMode.ifpossible)
solve this issue for me

How to I save some data into userStorage in the Java/Kotlin Client Library for Actions on Google

I am trying to save some info in the userStorage in Kotlin
In javascript, I did the following
exports.saveFloor = (conv, floor) => {
conv.user.storage.floor = floor;
}
here is the client library
From Name Psychic:
#ForIntent("request_name_permission")
public ActionResponse requestNamePermission(ActionRequest request) {
ResponseBuilder response = getResponseBuilder(request);
String requestedPermission = ConstantsKt.PERMISSION_NAME;
response.getConversationData().put(DATA_KEY_REQUESTED_PERMISSION, requestedPermission);
String storageKey = STORAGE_KEY_NAME;
if (!request.getUserStorage().containsKey(storageKey)) {
Permission permission =
new Permission()
.setContext(formatResponse("permission_reason"))
.setPermissions(new String[] {requestedPermission});
response.add("PLACEHOLDER_FOR_PERMISSION");
response.add(permission);
} else {
String name = (String) request.getUserStorage().get(storageKey);
response.add(formatResponse("say_name", name));
response.endConversation();
}
return response.build();
}
I guess the snippet I was looking for is
Map<String, Object> storage = response.getUserStorage();
String requestedPermission =
(String) request.getConversationData().get(DATA_KEY_REQUESTED_PERMISSION);
if (requestedPermission.equals(ConstantsKt.PERMISSION_NAME)) {
String name = request.getUser().getProfile().getDisplayName();
storage.put(STORAGE_KEY_NAME, name);
response.add(formatResponse("say_name", name));
response.endConversation();
return response.build();
}
if (requestedPermission.equals(ConstantsKt.PERMISSION_DEVICE_COARSE_LOCATION)) {
String location = request.getDevice().getLocation().getCity();
storage.put(STORAGE_KEY_LOCATION, location);
showLocationOnScreen(request, response);
return response.build();
}
The equivalent of my javascript code into Kotlin would be
fun saveFloor(request: ActionRequest, floor: String) {
val response = getResponseBuilder(request)
val storage = response.userStorage as MutableMap
storage["floor"] = floor
}
Cheers to Nick for pointing me in the right direction