Kotlin Wi-Fi loss/bad signal during FTP transfer - kotlin

I'm nearly done creating an app that sends txt files, containing scanned data, to an ftp server.
The issue that I'm currently struggling with is: what if my Wi-Fi has terrible signal or no signal at all.
I noticed that my 'isOnline()' check works fine and that if there is no internet, it alerts the user. However a few hours ago I tested the app in the basement and noticed that when the Wi-Fi signal has no bars, it still sends the data but it gets lost somewhere along the way.
Currently the flow of the data is as follow:
user presses 'send'
check internet and if true, continue
clear content list and send
the content to viewmodel
viewmodel checks internet again before
creating the txt files
txt files get sent via FTP code below.
private fun sendTXT(result: String) {
try {
val name = "00_VER${LocalDateTime.now().format(fileNameFormatter)}.txt"
val path = getApplication<Application>().applicationContext.filesDir.path
.toString() + name
val f = File(path)
val isNewFileCreated: Boolean = f.createNewFile()
if (isNewFileCreated) {
f.writeText(result, Charsets.UTF_8)
}
val ftpClient = FTPClient()
ftpClient.addProtocolCommandListener(PrintCommandListener(PrintWriter(System.out)))
ftpClient.connect("xxx.xx.xxx.xx", 21)
val reply: Int = ftpClient.replyCode
if (!FTPReply.isPositiveCompletion(reply)) {
ftpClient.disconnect()
throw IOException("Exception in connecting to FTP Server")
}
if (ftpClient.login("username", "pass")) {
ftpClient.enterLocalPassiveMode()
ftpClient.setFileType(FTP.BINARY_FILE_TYPE)
val inp = FileInputStream(f)
var directory = "/files/input"
ftpClient.changeWorkingDirectory(directory)
val result = ftpClient.storeFile(name, inp)
inp.close()
if (result) {
ftpClient.logout()
ftpClient.disconnect()
f.delete()
}
}
} catch (e: Exception) {
e.printStackTrace()
}
}
fun isOnline(context: Context): Boolean {
var result = false
val connectivityManager =
context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
val networkCapabilities = connectivityManager.activeNetwork ?: return false
val actNw =
connectivityManager.getNetworkCapabilities(networkCapabilities) ?: return false
result = when {
actNw.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) -> true
actNw.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) -> true
actNw.hasTransport(NetworkCapabilities.TRANSPORT_ETHERNET) -> true
else -> false
}
} else {
connectivityManager.run {
connectivityManager.activeNetworkInfo?.run {
result = when (type) {
ConnectivityManager.TYPE_WIFI -> true
ConnectivityManager.TYPE_MOBILE -> true
ConnectivityManager.TYPE_ETHERNET -> true
else -> false
}
}
}
}
return result
}
I'm stuck at finding a way to make sure the data gets to the server. Is there a more advanced way to check for internet connectivity?
I was considering adding all the scan objects as JSON to sharedpreferences, and if at the end of the day the user notices a scan didn't make it through, they can look up the missing scan and resend it.
However this seems very unconventional and I'm pretty sure there must be a better way to handle things.

Related

onSensorChanged function is called in an other app but not in mine (Kotlin)

i want to implement a step counter in my app, so i search how to make that and i found lot of differents implementations.
I notably found an app on GitHub which works. I have tried to implement this code in my app and in an other "test" app but any of them works and i don't no why.
The problem is caused by the onSensorChanged function of my STEP_COUNTER which is not called.
I have search in all the files of the app and i don't found the problem.
If somebody have a solution...
(I'm french so sorry if it's badly written)
the code i use:
private var sensorManager: SensorManager? = null
// Creating a variable which will give the running status
// and initially given the boolean value as false
private var running = false
// Creating a variable which will counts total steps
// and it has been given the value of 0 float
private var totalSteps = 0f
// Creating a variable which counts previous total
// steps and it has also been given the value of 0 float
private var previousTotalSteps = 0f
//in the onCreate
loadData()
resetSteps()
// Adding a context of SENSOR_SERVICE as Sensor Manager
sensorManager = getSystemService(Context.SENSOR_SERVICE) as SensorManager
override fun onResume() {
super.onResume()
mainHandler.post(pingRunnable)
binding.map.onResume()
running = true
// Returns the number of steps taken by the user since the last reboot while activated
// This sensor requires permission android.permission.ACTIVITY_RECOGNITION.
// So don't forget to add the following permission in AndroidManifest.xml present in manifest folder of the app.
val stepSensor = sensorManager?.getDefaultSensor(Sensor.TYPE_STEP_COUNTER)
if (stepSensor == null) {
// This will give a toast message to the user if there is no sensor in the device
Toast.makeText(this, "No sensor detected on this device", Toast.LENGTH_SHORT).show()
} else {
// Rate suitable for the user interface
sensorManager?.registerListener(this, stepSensor, SensorManager.SENSOR_DELAY_UI)
}
}
override fun onSensorChanged(event: SensorEvent?) {
// Calling the TextView that we made in activity_main.xml
// by the id given to that TextView
var tvStepsTaken = findViewById<TextView>(R.id.step)
if (running) {
totalSteps = event!!.values[0]
// Current steps are calculated by taking the difference of total steps
// and previous steps
val currentSteps = totalSteps.toInt() - previousTotalSteps.toInt()
// It will show the current steps to the user
tvStepsTaken.text = ("$currentSteps")
}
}
private fun resetSteps() {
var resetButton = findViewById<Button>(R.id.reset)
resetButton.setOnClickListener {
// This will give a toast message if the user want to reset the steps
previousTotalSteps = totalSteps
// When the user will click long tap on the screen,
// the steps will be reset to 0
testFragment?.binding?.step?.text = 0.toString()
// This will save the data
saveData()
true
}
}
private fun saveData() {
// Shared Preferences will allow us to save
// and retrieve data in the form of key,value pair.
// In this function we will save data
val sharedPreferences = getSharedPreferences("myPrefs", Context.MODE_PRIVATE)
val editor = sharedPreferences.edit()
editor.putFloat("key1", previousTotalSteps)
editor.apply()
}
private fun loadData() {
// In this function we will retrieve data
val sharedPreferences = getSharedPreferences("myPrefs", Context.MODE_PRIVATE)
val savedNumber = sharedPreferences.getFloat("key1", 0f)
// Log.d is used for debugging purposes
Log.d("MainActivity", "$savedNumber")
previousTotalSteps = savedNumber
}
override fun onAccuracyChanged(sensor: Sensor?, accuracy: Int) {
// We do not have to write anything in this function for this app
}

Java Selector for socket client not waked up after changing of interested ops from different thread

I use Java Selector for both server and client. For Server side it works perfect. It stops the thread when i call select() and wakes up when i change interest ops and it is ready for this operation..
But unfortunatelt it does not work for the same way for socket client. It stops the thread and does not wake up for reading or writing when i change interestedOps.
Creation of client connection:
selector = Selector.open()
SocketChannel.open().apply {
configureBlocking(false)
connect(address)
val key = socket.register(selector, SelectionKey.OP_READ or SelectionKey.OP_CONNECT)
val connection = ClientConnection(key) // Some stuff to hold the key for events
key.attach(connection)
}
Handle selection inside while loop:
val readyChannels = selector.select()
if (readyChannels == 0) continue
val keyIterator = selector.selectedKeys().iterator()
while (keyIterator.hasNext()) {
val key = keyIterator.next()
when (key.readyOps()) {
SelectionKey.OP_CONNECT -> {
val socket = (key.channel() as SocketChannel)
socket.finishConnect()
key.interestOps(key.interestOps() and SelectionKey.OP_CONNECT.inv())
// WORKS FINE!!!!!
key.interestOps(key.interestOps() and SelectionKey.OP_WRITE)
// Does not work at all. Selector will not wake up!
Thread(){
key.interestOps(key.interestOps() and SelectionKey.OP_WRITE)
}.start()
}
SelectionKey.OP_READ -> readPackets(key)
SelectionKey.OP_WRITE -> writePackets(key)
SelectionKey.OP_READ or SelectionKey.OP_WRITE -> {
writePackets(key)
readPackets(key)
}
}
keyIterator.remove()
}
So. The changing of interestOps from different thread does not work for socket clients. But it works fine for Server sockets..
Found solutions:
selector.select(300) -> use some timeout to wake up selector
selector.selectNow() -> use non blocking method and check the count of evetns
selector.wakeUp() -> save instance and wakeup it manually..
The question is Why it does not work ? Did I do some mistake? Something Missed?
UPD: Server side socket and selector
Creation of server socket:
selector = Selector.open()
serverSocket = ServerSocketChannel.open().apply {
socket().bind(address)
configureBlocking(false)
register(selector, SelectionKey.OP_ACCEPT)
}
Iteration of the selector inside Loop:
val readyChannels = selector.select()
if (readyChannels == 0) continue
val keyIterator = selector.selectedKeys().iterator()
while (keyIterator.hasNext()) {
val key = keyIterator.next()
when (key.readyOps()) {
SelectionKey.OP_ACCEPT -> {
val socket = serverSocket.accept().apply {
configureBlocking(false)
}
val client = clientFactory.createClient(selector,socket)
// Coroutines with Another thread context.
// There interestOps will be changed to send first data
_selectionAcceptFlow.tryEmit(client)
}
SelectionKey.OP_READ -> readPackets(key)
SelectionKey.OP_WRITE -> writePackets(key)
SelectionKey.OP_READ or SelectionKey.OP_WRITE -> {
writePackets(key)
readPackets(key)
}
}
keyIterator.remove()
}
If you call key.setInterestOps from a separate thread, you are creating a race condition between that call and the call to selector.select() in the client loop.
Your initial call to register does not contain SelectorKey.OP_WRITE. The first event triggered will be SelectorKey.OP_CONNECT. When handling that event, you indicate that in the future you are also interested in processing OP_WRITE.
If you do that in the same thread, then you are guaranteed that the interestOps are set the way you want them before the client loop reaches the call to selector.select(). If there is an OP_WRITE event available, you will process it immediatelly, otherwise the call blocks until it is available.
If you do that in a separate thread, then, depending on timing, you may run into a case where the client loop reaches the call to selector.select() and blocks even though there is an OP_WRITE event available. Since the separate thread did not yet change the interestOps, the OP_WRITE event is ignored.
I've included a self-contained example (client sending a message to server). To test different cases, you can comment/uncomment sections around line 90.
import java.net.InetSocketAddress
import java.nio.ByteBuffer
import java.nio.channels.SelectionKey
import java.nio.channels.Selector
import java.nio.channels.ServerSocketChannel
import java.nio.channels.SocketChannel
import java.util.concurrent.CountDownLatch
val address = InetSocketAddress("localhost", 5454)
fun main() {
val serverSocketSignal = CountDownLatch(1)
Thread {
startServer(serverSocketSignal)
}.start()
Thread {
startClient(serverSocketSignal)
}.start()
}
fun startServer(serverSocketSignal: CountDownLatch) {
//prepare server socket
val selector = Selector.open()
val serverSocket = ServerSocketChannel.open().apply {
socket().bind(address)
configureBlocking(false)
register(selector, SelectionKey.OP_ACCEPT)
}
serverSocketSignal.countDown();
//run server loop
while (true) {
println("Server loop")
val readyChannels = selector.select()
if (readyChannels == 0) continue
val keyIterator = selector.selectedKeys().iterator()
while (keyIterator.hasNext()) {
val key = keyIterator.next()
when (key.readyOps()) {
SelectionKey.OP_ACCEPT -> {
println("Server ACCEPT")
val socket = serverSocket.accept().apply {
configureBlocking(false)
}
socket.register(selector, SelectionKey.OP_READ)
}
SelectionKey.OP_READ -> {
val buffer = ByteBuffer.allocate(1024)
val count = (key.channel() as SocketChannel).read(buffer)
val message = String(buffer.array(), 0, count)
println("Server READ - " + message)
}
}
keyIterator.remove()
}
}
}
fun startClient(serverSocketSignal: CountDownLatch) {
serverSocketSignal.await();
//prepare client socket
val selector = Selector.open()
SocketChannel.open().apply {
configureBlocking(false)
connect(address)
register(selector, SelectionKey.OP_CONNECT or SelectionKey.OP_READ)
}
//run client loop
while (true) {
println("Client loop")
val readyChannels = selector.select()
if (readyChannels == 0) continue
val keyIterator = selector.selectedKeys().iterator()
while (keyIterator.hasNext()) {
val key = keyIterator.next()
when (key.readyOps()) {
SelectionKey.OP_CONNECT -> {
println("Client CONNECT")
val socket = (key.channel() as SocketChannel)
socket.finishConnect()
key.interestOpsAnd(SelectionKey.OP_CONNECT.inv())
/*
This works
*/
key.interestOps(SelectionKey.OP_WRITE)
/*
This doesn't work because we're And-ing the interestOps an the OP_WRITE op was not specified when calling register()
*/
// key.interestOpsAnd(SelectionKey.OP_WRITE)
/*
This may or may not work, depending on which thread gets executed first
- it will work if the setting interestOps=OP_WRITE in the new thread gets executed before the selector.select() in the client loop
- it will not work if selector.select() in the client loop gets executed before setting interestOps=OP_WRITE in the new thread,
since there won't be anything to process and the selector.select() gets blocked
On my machine, pausing the client loop even for a small duration was enough to change the result (e.g. the Thread.sleep(1) below).
* */
// Thread {
// println("Client setting interestedOps to OP_WRITE from new thread")
// key.interestOps(SelectionKey.OP_WRITE)
// }.start()
// //Thread.sleep(1)
}
SelectionKey.OP_WRITE -> {
println("Client WRITE")
val buffer = ByteBuffer.wrap("test message from client".toByteArray());
(key.channel() as SocketChannel).write(buffer)
key.interestOps(0)
}
}
keyIterator.remove()
}
}
}
As for why it works for you on the server side - you would have to share the full code for the server and client (might be a timing issue or your selector might be woken up by some events you did not intend to listen for). The snippets provided in the question do not contain enough infomation.

How to have Kotlin "Listen" when a function finish executing Successfully

This is my first time using Kotlin, I have to write a simple command-line application where it takes a list of user input strings. Valid inputs are only "Apple" or "Orange" and calculate the price (which is 60 cents and 25 cents respectively). I'm having some trouble with the 3rd requirement
"Build a service that listens for when orders are complete and sends a notification to the customer regarding its status and estimated delivery time. The Mail service subscribes to events from the Orders service and publishes the appropriate event that the customer (you) is able to read from the terminal"
this is what I have done so far
MainApp.tk
import java.util.Scanner
import kotlin.system.exitProcess;
import app.Checkout;
var shopRunning = true;
var applecount = 0;
fun main(args: Array<String>) {
while (shopRunning) {
println("Welcome to Express Store");
println("1. Checkout");
println("2. exit");
var userOption = 0;
//request the user to eneter an option
//if user eneter a options that is not valid it will keep looping til option that is enterd is accepted;
var userSeletedOption = false;
val inputScanner = Scanner(System.`in`);
while (!userSeletedOption) {
print("Select an Option: ");
userOption = inputScanner.nextInt();
//if input entered by the user is not accepted and invaliud message is printed and is promted to enter an option again.
if (userOption != 1 && userOption != 2) {
println("Invalid input detected!");
} else {
userSeletedOption = true;
}
}
if (userOption == 1) {
val checkout = Checkout();
println("We currently have apples and oranges in Stock.")
var list: MutableList<String> = ArrayList();
println(list.size);
var doneAddingToCart = false;
while(!doneAddingToCart){
print("enter name of item to be enter or exit to finish adding to the cart: ")
var item = inputScanner.next();
if(item.equals("exit")){
doneAddingToCart=true;
}
else{
list.add(item);
}
}
if(checkout.verify(list)){ //checks if list has any item that is not an apple or orange
println("Thank you for your Pruchse");
val cost = checkout.Chasher(list)
println("You bought: "+ list.toString());
print("your total is: "+ cost);//returns the total cost
exitProcess(1);//exits from the application
}
} else if (userOption == 2) {
print("Have a great day.");
exitProcess(1);
}
}
}
CheckOut.tk
class Checkout {
//checks if the user entered any invaild items
public fun verify (cart: MutableList<String>) : Boolean{
for(item in cart){
if(!item.equals("Apple") && !item.equals("Orange")){
return false;
}
}
return true;
}
public fun Chasher (cart: MutableList<String>) : Double{
var total = 0.0;
var orangecount = 0;//step 2 offers
var applecount = 0;//step 2 offers
for(item in cart){//step 1 function
if(item.equals("Apple") || item.equals("apple")){
applecount+=1;
total= total + 0.6;
}
if(item.equals("Orange") || item.equals("orange")){
orangecount +=1;
total=total +0.25;
}
}
if(orangecount ==3){//buy three for the price of 2.step 2
println("You qaulidified for our buy 3 oragnes for the price of 2 offer")
total -=0.25;
}
if(applecount ==1){//buy one aple get 1 free. step 2
println("You buy 1 apple get one free")
cart.add("Apple");
}
return total;
}
}
I don't need to send an email just send a message to the command line. Currently, I'm just printing messages (just to see if what I currently have even works). Yeah, I know there many spelling errors, english and writing was never my strongest subject
I can only provide three hints that might help you:
If you exit your program using System.exit, use 0 if the run did not have any problem. (Excerpt from JavaDoc: "The argument serves as a status code; by convention, a nonzero status code indicates abnormal termination.")
For checking equality, simply use == which corresponds to equals in Java. In your special case however, you can use item.equals("apple", ignoreCase=true) or simply item.equals("apple", true).
I'm not sure what the author of your task exactly expects as a solution.
In can imagine you are expected to use lambdas.
An example: Your could refactor your Checkout class like that:
class Checkout {
/**
* Checks if the given [cart] contains only apples and oranges,
* and calls [onSuccess].
* If also other articles are contained, [onSuccess] is not called.
*/
fun verify(cart: List<String>, onSuccess: (List<String>) -> Unit): Unit {
for (item in cart) {
if (!item.equals("apple", true) && !item.equals("Orange", true)) {
return
}
}
onSuccess(cart)
}
}
And then call
val cart = listOf("Orange", "Apple", "apple", "orange")
Checkout().verify(cart, { cart: List<String> ->
println("Thanks you for your purchase: $cart")
})
or even shorter (curly brackets are outside of parenthesis)
Checkout().verify(cart) { cart: List<String> ->
println("Thanks you for your purchase: $cart")
}
What I did here was to extract what is executed if your validation succeeds:
For that, I used a lambda function that accepts a list of articles/strings (List<String>) and returns something I ignore/don't care about -> Unit.
The advantage of that approach is that callers of your verify method can decide what to do on success at their liking because they can pass a lambda function around like any other variable. Here:
val cart = listOf("Orange", "Apple", "apple", "orange")
val onSuccess = { cart: List<String> ->
println("Thanks you for your purchase: $cart")
}
Checkout().verify(cart, onSuccess)
You could also extend Checkout to allow an observer to register.
I deliberately kept the code very simple. Normally you would allow multiple observers to register, only expose what clients are supposed to see and hide the rest, etc.
class Checkout(
val onSuccess : (List<String>) -> Unit
) {
fun verify(cart: List<String>): Unit {
for (item in cart) {
if (!item.equals("apple", true) && !item.equals("Orange", true)) {
return
}
}
onSuccess(cart)
}
}
val checkout = Checkout({ cart: List<String> ->
println("Thanks you for your purchase: $cart")
})
and then
val cart = listOf("Orange", "Apple", "apple", "orange")
checkout.verify(cart)
Be sure to check out https://play.kotlinlang.org/byExample/04_functional/01_Higher-Order%20Functions to learn more about lambda / higher-order functions.

I want send a filepart image with Vertx, I want replicate this case in code like Postman

PostmanExample
fun sendFileToMatch(path:String){
val client = WebClient.create(vertx);
var form = MultipartForm.create()
.binaryFileUpload("image","imageName" , path, "image/jpeg")
client.post(8888, "localhost", "/search?")
.putHeader("content-type", "multipart/form-data")
.sendMultipartForm(form) { }
}
when I run the code show bad request I have put exactly key "image" and send filepart image
TL;DR - your client code seems fine.
The only suspicious part is the path itself, as you don't specify how exactly you get it in your code, and the fact that you didn't specify how you handle response from the server: you just do {} in your example
Here is a fully working example for you to refer to, though:
val vertx = Vertx.vertx()
val router = Router.router(vertx)
router.route().handler(BodyHandler.create());
router.post("/search").handler {
val uploads: Set<FileUpload> = it.fileUploads()
uploads.forEach { upload ->
println(upload.name()) // "image"
println(upload.fileName()) // "imageName"
println(upload.size()) // 42537
}
it.response().end("OK!")
}
vertx.createHttpServer().requestHandler(router)
.listen(8888)
// We read the PNG file from /resources
val path = object {}.javaClass.getResource("5EWx9.png").path
val form = MultipartForm.create()
.binaryFileUpload("image","imageName" , path, "image/png")
val client = WebClient.create(vertx);
client.post(8888, "localhost", "/search?")
.putHeader("content-type", "multipart/form-data")
.sendMultipartForm(form) {
if (it.succeeded()) {
println(it.result().bodyAsString()) // "OK!"
}
else {
println(it.cause())
}
}
As the file to upload, I used the PostmanExample you've provided, which is a PNG image, which I put in the /resources directory of my project.

Scala Actors suspends unexpected when connecting to a database

I have a problem with my understanding of the standard actor library in Scala. In the code below I have created a simple swing, which basically should test if it is able to connect to a postgreSQL server. However it doesnt make it that far, I use Actors since the UI otherwise would freeze up while doing the work needed to connect to the database.
When er i use this line (meaning that I use actors instead of a single thread)
PostgresCheck ! new GetInfo()
The Swing will never be updated. However if I comment the line out and use the next three lines. (meaning the actors wont be used)
val result = PostgresCheck.checkPostgreSQL
if (result == "OK") pgText.background = GREEN else pgText.background = RED
pgText.text = result
The Swing will freeze but after about 25 seconds the swing will be updated.
import dbc.Database
import dbc.vendor.PostgreSQL
import java.awt.Dimension
import java.net.URI
import java.sql.Connection
import swing.event._
import swing._
import actors.Actor
import java.awt.Color._
import scala.actors.Actor._
case class Info(reply: String)
case class GetInfo()
object Example extends SimpleSwingApplication {
val pgButton = new Button("Check PostgreSQL")
val pgText = new TextArea("Not Checked Yet")
val pgPanel = new GridPanel(1, 2)
pgPanel.contents += pgButton
pgPanel.contents += pgText
def top = new MainFrame {
title = "StateChecker"
contents = pgPanel
}
listenTo(pgButton)
reactions += {
case e: ButtonClicked if (e.source.eq(pgButton)) => {
PostgresCheck ! new GetInfo()
//val result = PostgresCheck.checkPostgreSQL
//if (result == "OK") pgText.background = GREEN else pgText.background = RED
//pgText.text = result
}
}
val guiActor = new Actor {
def act() = {
loop {
react {
case e: String => {
val result = e
if (result == "OK") pgText.background = GREEN else pgText.background = RED
pgText.text = result
}
case e => println(e.toString)
}
}
}
}
guiActor.start
}
object PostgresCheck extends Actor {
def checkPostgreSQL() = {
try {
val db = new Database(myPgSQL)
val con: Connection = myPgSQL.getConnection // Freezes while doing this method
val statement = con.createStatement
if (statement.getResultSet.getMetaData.getColumnCount == 1) "OK"
else statement.getWarnings.toString
}
catch {
case e => e.toString
}
}
def act() = {
loop {
react {
case e: GetInfo => {
sender ! new Info(checkPostgreSQL)
}
}
}
}
start()
}
object myPgSQL extends PostgreSQL {
val uri = new URI("jdbc:postgresql://whatever.com")
val user = "1234"
val pass = "1234"
}
You are sending the message outside an actor, it seems. Try this:
Actor.actor { PostgresCheck ! new GetInfo() }
Not sure if it will help, but it is standard advise.
And, now that I think of it, to whom will the answer be sent? You are replying to the non-existent sender. I suppose you want the answer going to guiActor, but I don't see you doing so.
Okay here we go, the problem was related to the line
sender ! new Info(checkPostgreSQL)
It should actually have been
Example.guiActor! new Info(checkPostgreSQL)
For some reason related to the Actor library it actually suspends when waiting for the database connection, and wont return because of an unknown sender. For instance the following lines result in a printout of just a single line in console with "1".
val db = new Database(myPgSQL)
println("1")
// Freezes while doing this method
val con: Connection = myPgSQL.getConnection
println("2")
When changing the mentioned line, the code behave as expected.