Netty wss socket client drops connection - sockets

Trying to setup basic wss client. Channel is activated, but then immediately disconnected without any exception.
Client:
class WebSocketClient(val uri: String) {
lateinit var ch: Channel
fun connect() {
val bootstrap = Bootstrap()
val uri: URI = URI.create(uri)
val handler = WebSocketClientHandler(WebSocketClientHandshakerFactory.newHandshaker(uri, WebSocketVersion.V13, null, false, HttpHeaders.EMPTY_HEADERS, 1280000))
bootstrap.group(NioEventLoopGroup())
.channel(NioSocketChannel::class.java)
.handler(object : ChannelInitializer<SocketChannel>() {
override fun initChannel(ch: SocketChannel) {
val pipeline = ch.pipeline()
pipeline.addLast("http-codec", HttpClientCodec())
pipeline.addLast("aggregator", HttpObjectAggregator(65536))
pipeline.addLast("ws-handler", handler)
}
})
ch = bootstrap.connect(uri.host, 443).sync().channel()
handler.channelPromise.sync()
}
}
Handler:
class WebSocketClientHandler(val handShaker: WebSocketClientHandshaker) : SimpleChannelInboundHandler<Any>() {
lateinit var channelPromise: ChannelPromise
override fun handlerAdded(ctx: ChannelHandlerContext) {
channelPromise = ctx.newPromise()
}
override fun channelActive(ctx: ChannelHandlerContext) {
handShaker.handshake(ctx.channel())
}
override fun channelRead0(ctx: ChannelHandlerContext, msg: Any) {
val ch = ctx.channel()
if (!handShaker.isHandshakeComplete) {
handShaker.finishHandshake(ch, msg as FullHttpResponse)
channelPromise.setSuccess()
return
}
val frame = msg as WebSocketFrame
if (frame is TextWebSocketFrame) {
println("text message: $frame")
} else if (frame is PongWebSocketFrame) {
println("pont message")
} else if (frame is CloseWebSocketFrame) {
ch.close()
} else {
println("unhandled frame: $frame")
}
}
}
The flow of handler calls:
handleAdded
channelRegistered
channelActive
channelReadComplete
channelInactive
channelUnregistered
handlerRemoved
Is there something I miss?

You forgot to add a SSLHandler, this handler is needed because you are connecting to the https port (443), so the remote server expects all the traffic to be encrypted. Sending a unencrypted message to the https port has undefined behaviour, some server will shut down your connection, other servers will send a redirect back to https.
You can add an sslhandler using the following way:
java:
final SslContext sslCtx = SslContextBuilder.forClient()
// .trustManager(InsecureTrustManagerFactory.INSTANCE)
.build();
pipeline.addLast("ssl-handler", sslCtx.newHandler(ch.alloc(), url.getHost(), 443));
// Your remaining code....
pipeline.addLast("http-codec", new HttpClientCodec())

Related

MongoDB connection is not connecting to client in localhost

Setting up a MEAN stack project I'm trying to connect mongodb connection but it is failing. Below is my code. Let me know if any changes required here. Thank you
In my connect.ts file
import { MongoClient } from 'mongodb';
export class MongoUtility {
static readonly collectionNames = {
stockList: 'StockList'
};
private _mongoClient: MongoClient;
private _tradeTrackDb;
private _connectionStatus: ConnectionStatus;
constructor() {
this._mongoClient = new MongoClient('mongodb://localhost:27017');
this._init();
}
private _init() {
this._connectDb();
}
private _connectDb() {
this._connectionStatus = ConnectionStatus.Connecting;
this._mongoClient.connect()
.then(client => {
const db = client.db().collection('TradeTrack');
this._tradeTrackDb = db;
this._tradeTrackDb.on('close', () => {
this._connectionStatus = ConnectionStatus.Reconnecting;
console.log('Lost connection to TradeTrackDB. Attempting to reconnect...');
});
this._tradeTrackDb.on('reconnect', () => {
this._connectionStatus = ConnectionStatus.Connected;
console.log('Recovered connection to TradeTrackDB.');
})
}).catch((error) => {
console.warn('Initial connection attempt to TradeTrackDB failed. Attempting reconnect in 5 seconds.', JSON.stringify(error));
setTimeout(this._connectDb.bind(this), 5000);
})
}
}
enum ConnectionStatus {
Connecting,
Connected,
Reconnecting
}
Its coming to catch of connectDb method everytime.
Error
Initial connection attempt to TradeTrackDB failed. Attempting reconnect in 5 seconds. {"reason":{"type":"Unknown","servers":{},"stale":false,"compatible":true,"heartbeatFrequencyMS":10000,"localThresholdMS":15,"setName":null,"maxElectionId":null,"maxSetVersion":null,"commonWireVersion":0,"logicalSessionTimeoutMinutes":null}}

When is good to close (release) the SQLConnection and SqlConnection in Vert.x?

Taking a piece from Vert.x website example:
private Future<Void> prepareDatabase() {
Promise<Void> promise = Promise.promise();
dbClient = JDBCClient.createShared(vertx, new JsonObject() //(1)
.put("url", "jdbc:hsqldb:file:db/wiki") //(2)
.put("driver_class", "org.hsqldb.jdbcDriver") //(3)
.put("max_pool_size", 30)); //(4)
dbClient.getConnection(ar -> { //(5)
if (ar.failed()) {
LOGGER.error("Could not open a database connection", ar.cause());
promise.fail(ar.cause()); //(6)
} else {
SQLConnection connection = ar.result(); //(7)
connection.execute(SQL_CREATE_PAGES_TABLE, create -> {
connection.close(); //(8)
if (create.failed()) {
LOGGER.error("Database preparation error", create.cause());
promise.fail(create.cause());
} else {
promise.complete(); //(9)
}
});
}
});
return promise.future();
}
In (8), the connection is closed at the very beginning of the handler. What if we execute a query and then iterate the result in the handler:
private fun jdbcQuery(sql: String, params: JsonArray): Future<ResultSet> {
val promise: Promise<ResultSet> = Promise.promise()
getJDBCClient().getConnection { ar ->
if (ar.succeeded()) {
val connection = ar.result()
connection.queryWithParams(sql, params) { res ->
connection.close() //(10) release the connection
if (res.succeeded()) {
val result = res.result()
promise.complete(result)
} else {
promise.fail(res.cause())
}
}
} else {
promise.fail(ar.cause())
}
}
return promise.future()
}
I can fetch the data inside if (res.succeeded()).
My question is: why we can close and release the connection before iterating to fetch data? How does it work?
The queryWithParams API fetches the entire response from the DB when it is executed. Results are not fetched lazily. For this reason, it is safe to close the connection at the beginning of your response handler callback, because by that time the entire result set has already been received by the client. Results are only fetched lazily when you use the queryStream API. If you were using that API, you would want to wait to close the connection until all the results were received.

How to get custom header from response (retrofit & rxjava)

I am trying to get some custom HTTP headers from all the REST API responses in my code.
Here is how I initiate the client:
private fun initializeClient(): OkHttpClient {
val interceptor = HttpLoggingInterceptor()
interceptor.level = HttpLoggingInterceptor.Level.BODY
val httpClient = OkHttpClient.Builder()
.addInterceptor(object : Interceptor {
override fun intercept(chain: Interceptor.Chain): Response {
val original = chain.request()
val request = original.newBuilder()
.header("Content-Type", "application/json")
.method(original.method, original.body)
.build()
return chain.proceed(request)
}
})
.addInterceptor(interceptor)
.build()
return httpClient
}
private fun initializeApi() {
api = Retrofit.Builder()
.baseUrl(API_BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.client(initializeClient())
.build()
.create(RestApi::class.java)
}
Here is a sample of the retrofit implementation:
#POST("/register")
fun registerUser(#Body registerPostData: RegistrationForm): Single<RegistrationResponse>
and the ViewModel part:
disposable.add(
api.registerUser(form)
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribeWith(object : DisposableSingleObserver<Member>() {
override fun onSuccess(value: RegistrationResponse?) {
// no headers in here
response.value = value
}
override fun onError(e: Throwable?) {
}
})
)
The server returns some x-custom-header in all API responses, which I need to capture in all calls.
Thank you!
Change your retrofit class to return a Response:
#POST("/register")
fun registerUser(#Body registerPostData: RegistrationForm): Single<Response<RegistrationResponse>>
then:
override fun onSuccess(result: Response<RegistrationResponse>?) {
// get header from response.headers()
}

Kotlin & Retrofit: Simple POST without Response

I'm trying to do a POST Request with Kotlin and Retrofit where I'm only interested in the statuscode of the request. Tutorials I have seen solve it all a bit different and most of the time they do not compile any more or are very complicated.
Can someone help improving this code:?
interface ClientService {
#POST("user/password-reset")
fun passwortReset(#Query("email") email: String): Observable<Result>
companion object {
fun create(): ClientService {
val retrofit = Retrofit.Builder()
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.addConverterFactory(GsonConverterFactory.create())
.baseUrl("https://test-backend.myurl.com/api/")
.build()
return retrofit.create(ClientService::class.java)
}
}
}
I'm not sure how to call it and how to get the statuscode.
Try this example
Under build.gradle:
// retrofit
compile "com.squareup.retrofit2:retrofit:2.3.0"
compile "com.squareup.retrofit2:adapter-rxjava2:2.3.0"
compile "com.squareup.retrofit2:converter-gson:2.3.0"
// rxandroid
compile "io.reactivex.rxjava2:rxandroid:2.0.1"
compile 'com.squareup.okhttp3:logging-interceptor:3.4.1'
compile 'com.squareup.okhttp3:okhttp:3.4.1'
Interface:
interface APIService {
#POST("register")
#FormUrlEncoded
fun registrationPost(#Field("email") email: String,
#Field("password") password: String): Call<Registration>}
//**App Utils**
object ApiUtils {
val BASE_URL = "your_url"
val apiService: APIService
get() = RetrofitClient.getClient(BASE_URL)!!.create(APIService::class.java)
}
Retrofit Client:
object RetrofitClient {
var retrofit: Retrofit? = null
fun getClient(baseUrl: String): Retrofit? {
if (retrofit == null) {
//TODO While release in Google Play Change the Level to NONE
val interceptor = HttpLoggingInterceptor()
interceptor.level = HttpLoggingInterceptor.Level.BODY
val client = OkHttpClient.Builder()
.addInterceptor(interceptor)
.connectTimeout(100, TimeUnit.SECONDS)
.readTimeout(100, TimeUnit.SECONDS)
.build()
retrofit = Retrofit.Builder()
.client(client)
.baseUrl(baseUrl)
.addConverterFactory(GsonConverterFactory.create())
.build()
}
return retrofit
}
}
MainActivity
//Variable declaration
var mAPIService: APIService? = null
//After oncreate
mAPIService = ApiUtils.apiService
//Some Button click
mAPIService!!.registrationPost("SampleTest2#gamil.com", "123456").enqueue(object : Callback<Registration> {
override fun onResponse(call: Call<Registration>, response: Response<Registration>) {
Log.i("", "post submitted to API." + response.body()!!)
if (response.isSuccessful()) {
Log.i("", "post registration to API" + response.body()!!.toString())
Log.i("", "post status to API" + response.body()!!.status)
Log.i("", "post msg to API" + response.body()!!.messages)
}
}
override fun onFailure(call: Call<Registration>, t: Throwable) {
}
})
Inside any function you have to call like:
fun resetPassword(email:String) {
val clientService = ClientService.create(APIConstants
.BASE_URL_WORKSPACE)
addSubscription(apiService.login(APIConstants.API_ACTION_LOGIN, userName, password,
deviceid), object : APICallback<UserLoginResponse>() {
override fun onSuccess(model: UserLoginResponse) {
if (TextUtils.isEmpty(model.errorMessage)) {
mvpView.getDataSuccess(model, apiRequestCode)
} else {
mvpView.getDataFail(model.errorMessage, apiRequestCode)
}
}
override fun onFailure(msg: String?) {
LogUtil.e("Login Failure()- " + msg!!)
}
override fun onFinish() {}
})
}
You will get the success response/result in onSuccess() method.
There is lot's of answers for the same question. Main Funda is to Call Post API using Retrofit.
Let me make some easier things to call Any API.
In this Example of code. i used Demo API from https://jsonplaceholder.typicode.com/
First takes Permission in AndroidManifest.xml
<uses-permission android:name="android.permission.INTERNET" />
Now go create one interface for Post API Response.
interface ApiInterFace {
#POST("users")
fun sendUserData(#Body userPost: UserPost) : Call<UserPost>
}
Now Comes to MainActivity or your Target Activity to call the API.
in this method i used static dummy data for user.
private fun sendDataToApi() {
val retrofitBuilder = Retrofit.Builder()
.addConverterFactory(GsonConverterFactory.create())
.baseUrl("https://jsonplaceholder.typicode.com/") // Add Your BaseUrl here
.build()
val jsonPlaceHolder = retrofitBuilder.create(ApiInterFace::class.java)
val userPost = UserPost(1,1,"New Added","Body of the title") // Dummy Data
val call = jsonPlaceHolder.sendUserData(userPost)
call.enqueue(object : Callback<UserPost>{
override fun onResponse(call: Call<UserPost>, response: Response<UserPost>) {
Log.e("TAG", "onResponse: "+response.code() )
}
override fun onFailure(call: Call<UserPost>, t: Throwable) {
Log.e("TAG", "onFailure: "+t.message )
}
} )
}
This is only based on simple example of Post the data to server. There MayBe having changes as per your cases.

How can I do this redirection from ballerinalang?

I've implemented a REST endpoint in ballerinalang called https://localhost:9090/isValidUser. And here is my code below
import ballerina.net.http;
#http:configuration {
basePath:"/",
httpsPort:9090,
keyStoreFile:"${ballerina.home}/bre/security/wso2carbon.jks",
keyStorePassword:"wso2carbon",
certPassword:"wso2carbon",
trustStoreFile:"${ballerina.home}/bre/security/client-truststore.jks",
trustStorePassword:"wso2carbon"
}
service<http> authentication {
#http:resourceConfig {
methods:["POST"],
path:"/isValidUser"
}
resource isValidUser (http:Request req, http:Response res) {
println(req.getHeaders());
res.send();
}
}
Now I need to do is when I invoke that URL from the browser, I need to redirect the user to another URL called https://localhost:3000 after some validations happen within my service.
So how can I do this redirection from ballerinalang?
Ballerina has provided smooth API to do the redirection. Please check following code which elaborates the Listener endpoint redirection.
service<http:Service> redirect1 bind {port:9090} {
#http:ResourceConfig {
methods:["GET"],
path:"/"
}
redirect1 (endpoint client, http:Request req) {
http:Response res = new;
_ = client -> redirect(res, http:REDIRECT_TEMPORARY_REDIRECT_307,
["http://localhost:9093/redirect2"]);
}
}
The complete example is available in
Ballerina Redirects
In Ballerina, you need to handle the redirects yourself by setting the necessary headers and status code. The following example is a simple demo of how you can redirect in Ballerina. (note: I tried this in Ballerina 0.95.2)
import ballerina.net.http;
#http:configuration {basePath:"/hello"}
service<http> helloWorld {
#http:resourceConfig {
methods:["GET"],
path:"/"
}
resource sayHello (http:Request request, http:Response response) {
map qParams = request.getQueryParams();
var name, _ = (string)qParams.name;
if (isExistingUser(name)) {
response.setStringPayload("Hello Ballerina!");
} else {
response.setHeader("Location", "http://localhost:9090/hello/newUser");
response.setStatusCode(302);
}
_ = response.send();
}
#http:resourceConfig {path:"/newUser"}
resource newUser (http:Request request, http:Response response) {
string msg = "New to Ballerina? Welcome!";
response.setStringPayload(msg);
_ = response.send();
}
}
function isExistingUser (string name) (boolean) {
return name == "Ballerina";
}