1

I have a Golang server with an API created with the help of gin and gorm. It was working fine until recently when it's having some weird behavior. Before calling the API on my android app using Retrofit, I'd test it on Postman. Just yesterday, I tried to call the login API to get the JWT token that is needed for the other API calls I'd need later on. On Postman, the login was working fine. But yesterday, the login doesn't work on the android app anymore because of the SocketTimeoutException. And I don't know what's causing that. On Postman, it said that it only took 10-ish seconds to finish the call, and I already increased the timeout of Retrofit to 180s using these lines of code:

private val httpClient = OkHttpClient.Builder()
        .connectTimeout(180, TimeUnit.SECONDS)
        .writeTimeout(180, TimeUnit.SECONDS)
        .readTimeout(180, TimeUnit.SECONDS)

and the issue still persist. I'm not sure if a code I added on the server before is causing this, but it isn't being called right now. It's some code for starting a socket server, which doesn't seem to really work right now for some reason(even though it's an official sample code from googollee). Here it is:

package helpers

import (
    "fmt"
    "net/http"

    socketio "github.com/googollee/go-socket.io"
    "github.com/googollee/go-socket.io/engineio"
    "github.com/googollee/go-socket.io/engineio/transport"
    "github.com/googollee/go-socket.io/engineio/transport/polling"
    "github.com/googollee/go-socket.io/engineio/transport/websocket"
)

const (
    SERVER_HOST = "localhost"
    SERVER_PORT = "60051"
    SERVER_TYPE = "tcp"
)

var allowOriginFunc = func(r *http.Request) bool {
    return true
}

func StartSocket() {

    server := socketio.NewServer(&engineio.Options{
        Transports: []transport.Transport{
            &polling.Transport{
                CheckOrigin: allowOriginFunc,
            },
            &websocket.Transport{
                CheckOrigin: allowOriginFunc,
            },
        },
    })

    server.OnConnect("/", func(s socketio.Conn) error {
        s.SetContext("")
        fmt.Println("connected:", s.ID())
        return nil
    })

    server.OnEvent("/", "notice", func(s socketio.Conn, msg string) {
        fmt.Println("notice:", msg)
        s.Emit("reply", "have "+msg)
    })

    server.OnError("/", func(s socketio.Conn, e error) {
        fmt.Println("meet error:", e)
    })

    server.OnDisconnect("/", func(s socketio.Conn, reason string) {
        fmt.Println("closed", reason)
    })

    go server.Serve()
    defer server.Close()

    http.Handle("/socket.io/", server)
    http.Handle("/", http.FileServer(http.Dir("./asset")))

    fmt.Println("ScktSrv Serving at localhost:8000...")
    fmt.Print(http.ListenAndServe(":8000", nil))
}

Both the server and the emulator are running on my PC

UPDATE: Here's what the android code looks like, it's kinda complex but it's basically just a Retrofit call:

val username = binding.txtUsername.text.toString()
val password = binding.txtPassword.text.toString()

val account = Account(" ", " ", " ", username, password, mutableListOf())

scope.launch {
    val inAPIDataResp = retFetchHlpr.fetchAPIData{ atlAPI.loginAccount(account) }
    
    //some code for processing the received response
}

//Retrofit endpoint setup

@Headers("Content-Type: application/json")
    @POST("/account/login")
    suspend fun loginAccount(
        @Body data: Account
    ) : Response<AccountLoginResponse>

Here's the code from my helper class:

suspend fun <V> fetchAPIData(apiGetterFunc: suspend () -> Response<V>): V? {
    val actsResult: Response<V>?
    if( utils.isInternetAvailable(ctx) ){
        try{
            actsResult = apiGetterFunc.invoke()

            val respBody = retrofitErrorHandler(actsResult)
            if (respBody != null){
                return respBody
            }
        }catch (e: Exception){
            Log.e(TAG, "Retrofit Error: ${e.localizedMessage}")
        }
    }
    return null
}

private fun <T> retrofitErrorHandler(res: Response<T>): T {
    if (res.isSuccessful) {
        Log.d(TAG, "retrofitErrorHandler success: ${res.body()}")
        return res.body()!!
    } else {
        Log.d(TAG, "retrofitErrorHandler errMsg: ${res.errorBody().toString()}")
        throw Exception(res.errorBody().toString())
    }
}

The error I'm getting is:

Retrofit Error: failed to connect to /192.168.45.102 (port 5000) from /10.0.2.16 (port 54552) after 180000ms: isConnected failed: ETIMEDOUT (Connection timed out)

I tried connecting my PC and a tablet running the app to my phone's hotspot and I still get this error.

rminaj
  • 560
  • 6
  • 28

1 Answers1

1

I think I already found a solution. Adding .protocols(listOf(Protocol.HTTP_1_1)) for the OkHttpClient seems to make Retrofit work fine again. Found the answer here

rminaj
  • 560
  • 6
  • 28