Skip to content

Commit

Permalink
Refactor app to use Websockets
Browse files Browse the repository at this point in the history
  • Loading branch information
miloszwasacz committed Mar 21, 2020
1 parent f5cb647 commit 5236326
Show file tree
Hide file tree
Showing 14 changed files with 164 additions and 67 deletions.
5 changes: 3 additions & 2 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ android {
applicationId "com.gmail.miloszwasacz.tictactoe9x9"
minSdkVersion 23
targetSdkVersion 28
versionCode 2
versionName "0.2.1"
versionCode 3
versionName "0.3.0"

testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
Expand Down Expand Up @@ -54,4 +54,5 @@ dependencies {
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
implementation 'androidx.gridlayout:gridlayout:1.0.0'
implementation 'com.google.code.gson:gson:2.8.6'
implementation 'com.squareup.okhttp3:okhttp:4.4.1'
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ class BoardActivity: AppCompatActivity() {
private var currentDialog = -1

override fun onCreate(savedInstanceState: Bundle?) {
//Ustawianie motywu
setTheme(when(PreferenceManager.getDefaultSharedPreferences(this@BoardActivity).getString(getString(R.string.key_theme), "AppTheme")) {
getString(R.string.theme_dark) -> R.style.AppThemeDark
else -> R.style.AppTheme
Expand Down Expand Up @@ -272,6 +273,9 @@ class BoardActivity: AppCompatActivity() {
dialog.setTitle(R.string.dialog_join_title)
dialog.setMessage(resources.getString(R.string.dialog_join_description))
dialog.setCancelable(true)
dialog.setOnCancelListener {
finish()
}
}
//Wersja oprogramowania
else -> {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
@file:Suppress("DEPRECATION")
package com.gmail.miloszwasacz.tictactoe9x9

import android.os.AsyncTask

class CloseSocketTask(private val viewModel: CommunicationViewModel): AsyncTask<Void, Void?, Void?>() {
/*class CloseSocketTask(private val viewModel: CommunicationViewModel): AsyncTask<Void, Void?, Void?>() {
override fun doInBackground(vararg arg0: Void): Void? {
for(task in viewModel.communicationTaskList) {
Expand All @@ -16,13 +14,13 @@ class CloseSocketTask(private val viewModel: CommunicationViewModel): AsyncTask<
}
return null
}
}*/

override fun onPostExecute(result: Void?) {
/*override fun onPostExecute(result: Void?) {
if(viewModel.socket != null && !viewModel.socket!!.isClosed) {
viewModel.socket!!.shutdownInput()
viewModel.socket!!.shutdownOutput()
viewModel.socket!!.close()
}
}
}
}*/
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,15 @@ import java.io.BufferedReader

class CommunicationTask(private val viewModel: CommunicationViewModel, private val inputPacket: Packet?/*, private var socket: Socket, private var output: OutputStream, private var inputStream: InputStreamReader*/): AsyncTask<Void, Void?, Packet>() {
private lateinit var input: BufferedReader
private var inputStream = viewModel.inputStream
//private var inputStream = viewModel.inputStream

override fun onPreExecute() {
/*override fun onPreExecute() {
input = BufferedReader(inputStream)
if(inputPacket != null && inputPacket is PacketSTT) {
viewModel.currentGameState.value = Event(viewModel.createBoardState(inputPacket))
}
}
}*/

override fun doInBackground(vararg arg0: Void): Packet {
return if(!isCancelled) {
Expand All @@ -28,7 +28,7 @@ class CommunicationTask(private val viewModel: CommunicationViewModel, private v
else PacketBadErrDbgUin(method = "DBG", params = ParamsBadErrDbgUin("Task cancelled"), time = (System.currentTimeMillis()/1000L).toInt())
}

override fun onPostExecute(resultPacket: Packet) {
/*override fun onPostExecute(resultPacket: Packet) {
if(!isCancelled) {
when(resultPacket) {
//Odbieranie planszy
Expand Down Expand Up @@ -61,5 +61,5 @@ class CommunicationTask(private val viewModel: CommunicationViewModel, private v
else {
Log.i("state", (resultPacket as PacketBadErrDbgUin).params.msg)
}
}
}*/
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@ import androidx.lifecycle.MutableLiveData
import androidx.preference.PreferenceManager
import com.google.gson.Gson
import com.google.gson.reflect.TypeToken
import java.io.InputStreamReader
import java.io.OutputStream
import java.net.Socket
import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.WebSocket

open class CommunicationViewModel(application: Application): AndroidViewModel(application) {
//Dialogi
Expand All @@ -23,47 +23,65 @@ open class CommunicationViewModel(application: Application): AndroidViewModel(ap
val serverPORT = (PreferenceManager.getDefaultSharedPreferences(application).getString(application.getString(R.string.key_port), application.getString(R.string.default_port)) ?: application.getString(R.string.default_port)).toInt()

//Socket
var socket: Socket? = null
lateinit var output: OutputStream
lateinit var inputStream: InputStreamReader
val client = OkHttpClient()
var socket: WebSocket? = null
//lateinit var output: OutputStream
//lateinit var inputStream: InputStreamReader
val NORMAL_CLOSURE_STATUS = 1000

//Listy AsyncTask'ów
val communicationTaskList = ArrayList<CommunicationTask>()
val sendTaskList = ArrayList<SendTask>()
//val communicationTaskList = ArrayList<CommunicationTask>()
//val sendTaskList = ArrayList<SendTask>()
val interpretationTaskList = ArrayList<InterpretationTask>()

var currentGameState = MutableLiveData<Event<BoardModel>>()
var wrongSocket = MutableLiveData<Event<Boolean>>()
var versionPacket: PacketVER? = null

//Łączenie z serwerem
fun connect(roomName: String) {
ConnectTask(this@CommunicationViewModel, roomName).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR)
//ConnectTask(this@CommunicationViewModel, roomName).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR)
dialogId.value = Event(connectDialogId)
wrongSocket.value = Event(false)
val request = Request.Builder().url("ws://$serverIP:$serverPORT").build()
val listener = EchoWebSocketListener(this@CommunicationViewModel, roomName)
socket = client.newWebSocket(request, listener)
}

/*
//Odbieranie pakietu
fun communicate(packet: Packet?) {
val task = CommunicationTask(this@CommunicationViewModel, packet)
communicationTaskList.add(task)
task.execute()
}
}*/

//Wysyłanie ruchu gracza
fun sendMove(x: Int, y: Int) {
val task = SendTask(this@CommunicationViewModel, PacketSET(params = ParamsSET(x, y), time = (System.currentTimeMillis()/1000L).toInt()))
/*val task = SendTask(this@CommunicationViewModel, PacketSET(params = ParamsSET(x, y), time = (System.currentTimeMillis()/1000L).toInt()))
sendTaskList.add(task)
task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR)
task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR)*/
val packet = PacketSET(params = ParamsSET(x, y), time = (System.currentTimeMillis()/1000L).toInt())
socket?.send(Gson().toJson(packet))
}

//Wysyłanie odpowiedzi na Ping
fun sendPOG() {
val task = SendTask(this@CommunicationViewModel, PacketGetPngPog(method = "POG", params = ParamsGetPngPog(), time = (System.currentTimeMillis()/1000L).toInt()))
/*val task = SendTask(this@CommunicationViewModel, PacketGetPngPog(method = "POG", params = ParamsGetPngPog(), time = (System.currentTimeMillis()/1000L).toInt()))
sendTaskList.add(task)
task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR)
task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR)*/
val packet = PacketGetPngPog(method = "POG", params = ParamsGetPngPog(), time = (System.currentTimeMillis()/1000L).toInt())
socket?.send(Gson().toJson(packet))
}

//Zamykanie Socketa
override fun onCleared() {
CloseSocketTask(this@CommunicationViewModel).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR)
//CloseSocketTask(this@CommunicationViewModel).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR)
for(task in interpretationTaskList) {
if(task.status == AsyncTask.Status.RUNNING || task.status == AsyncTask.Status.PENDING)
task.cancel(false)
}
client.dispatcher.executorService.shutdown()
super.onCleared()
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,18 +1,8 @@
package com.gmail.miloszwasacz.tictactoe9x9

import android.os.AsyncTask
import android.util.Log
import com.google.gson.Gson
import java.io.BufferedReader
import java.io.IOException
import java.io.InputStreamReader
import java.io.OutputStream
import java.net.InetSocketAddress
import java.net.Socket


class ConnectTask(private var viewModel: CommunicationViewModel, private var roomName: String = "public"): AsyncTask<Void, Void?, String?>() {
private lateinit var socket: Socket

/*class ConnectTask(private var viewModel: CommunicationViewModel, private var roomName: String = "public"): AsyncTask<Void, Void?, Void?>() {
private lateinit var socket: WebSocket
private lateinit var output: OutputStream
private lateinit var inputStream: InputStreamReader
private val serverIP = viewModel.serverIP
Expand All @@ -21,27 +11,34 @@ class ConnectTask(private var viewModel: CommunicationViewModel, private var roo
override fun onPreExecute() {
viewModel.dialogId.value = Event(viewModel.connectDialogId)
viewModel.wrongSocket.value = Event(false)
socket = Socket()
val request = Request.Builder().url("ws://$serverIP:$serverPORT").build()
val listener = EchoWebSocketListener(viewModel)
socket = viewModel.client.newWebSocket(request, listener)
}
override fun doInBackground(vararg arg0: Void): String? {
override fun doInBackground(vararg arg0: Void): Void? {
/*
try {
socket.connect(InetSocketAddress(serverIP, serverPORT))
output = socket.getOutputStream()
val packet = Gson().toJson(PacketJON(params = ParamsJON(roomName), time = (System.currentTimeMillis()/1000L).toInt()))
output.write(packet.toByteArray(charset("UTF-8")))
sockSocketAddress(serverIP, serverPORT))
output = socket.getOutputStream()
val packet = Gson().toJson(PacketJON(params = ParamsJON(roomName), time = (System.currentTimeMillis()/1000L).toInt()))
output.write(packet.toByteArray(charset("UTF-8")))
inputStream = InputStreamReader(socket.getInputStream())
val input = BufferedReader(inputStream)
inputStream = InputStreamReader(socket.getInputStream())
val input = BufferedReader(inputStream)
val resultJSON = input.readLine()
Log.i("packet", resultJSON)
val resultJSON = input.readLine()
Log.i("packet", resultJSON)
return resultJSON
return resultJSON
}
catch(e: IOException) {
return null
}
return null
}*/
val packet = Gson().toJson(PacketJON(params = ParamsJON(roomName), time = (System.currentTimeMillis()/1000L).toInt()))
socket.send(packet)
return null
}
override fun onPostExecute(result: String?) {
Expand All @@ -57,4 +54,4 @@ class ConnectTask(private var viewModel: CommunicationViewModel, private var roo
viewModel.wrongSocket.value = Event(true)
}
}
}
}*/
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package com.gmail.miloszwasacz.tictactoe9x9

import android.util.Log
import com.google.gson.Gson
import okhttp3.Response
import okhttp3.WebSocket
import okhttp3.WebSocketListener


class EchoWebSocketListener(private val viewModel: CommunicationViewModel, private val room: String): WebSocketListener() {
override fun onOpen(webSocket: WebSocket, response: Response) {
val packet = Gson().toJson(PacketJON(params = ParamsJON(room), time = (System.currentTimeMillis()/1000L).toInt()))
webSocket.send(packet)
}

override fun onMessage(webSocket: WebSocket, text: String) {
val task = InterpretationTask(viewModel, text)
viewModel.interpretationTaskList.add(task)
task.execute()
//Log.i("Receiving", text)
}

override fun onClosing(webSocket: WebSocket, code: Int, reason: String) {
webSocket.close(viewModel.NORMAL_CLOSURE_STATUS, null)
Log.i("Closing", "$code / $reason")
}

override fun onFailure(webSocket: WebSocket, t: Throwable, response: Response?) {
Log.i("Error", t.message)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package com.gmail.miloszwasacz.tictactoe9x9

import android.os.AsyncTask
import android.util.Log

class InterpretationTask(private val viewModel: CommunicationViewModel, private val inputPacket: String): AsyncTask<Void, Void?, Packet>() {

override fun doInBackground(vararg arg0: Void): Packet {
return if(!isCancelled) {
viewModel.deserializePacketFromServer(inputPacket)
}
else PacketBadErrDbgUin(method = "DBG", params = ParamsBadErrDbgUin("Task cancelled"), time = (System.currentTimeMillis()/1000L).toInt())
}

override fun onPostExecute(resultPacket: Packet) {
if(!isCancelled) {
when(resultPacket) {
//Odbieranie planszy
is PacketSTT -> {
viewModel.dialogId.value = Event(viewModel.removeDialog)
viewModel.currentGameState.value = Event(viewModel.createBoardState(resultPacket))
}
//Wysłanie odpowiedzi na pakiet "PNG"
is PacketGetPngPog -> {
if(resultPacket.method == "PNG") {
viewModel.sendPOG()
}
}
//Wyświetlanie info o oprogramowaniu
is PacketVER -> {
viewModel.versionPacket = resultPacket
viewModel.dialogId.value = Event(viewModel.versionDialogId)
}
//Zapisywanie błędów itp. w Log'u
else -> {
Log.i("packetMSG", (resultPacket as PacketBadErrDbgUin).params.msg)
}
}
}
else {
Log.i("state", (resultPacket as PacketBadErrDbgUin).params.msg)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,28 +12,32 @@ import kotlinx.android.synthetic.main.activity_main.*
class MainActivity: AppCompatActivity() {

override fun onCreate(savedInstanceState: Bundle?) {
//Ustawianie motywu
setTheme(when(PreferenceManager.getDefaultSharedPreferences(this@MainActivity).getString(getString(R.string.key_theme), "AppTheme")) {
getString(R.string.theme_dark) -> R.style.AppThemeDark
else -> R.style.AppTheme
})
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)

//Dołączanie do pokoju
buttonJoin.setOnClickListener {
val intent = Intent(this@MainActivity, BoardActivity::class.java)
intent.putExtra("EXTRA_ROOM_NAME", when(editTextRoomName.text.toString().trim()) {
intent.putExtra("EXTRA_ROOM_NAME", when(val text = editTextRoomName.text.toString().trim()) {
"" -> "public"
else -> editTextRoomName.text.toString().trim()
else -> text
})
startActivity(intent)
}
}

//Pokazywanie ikonek
override fun onCreateOptionsMenu(menu: Menu?): Boolean {
menuInflater.inflate(R.menu.menu_main, menu)
return true
}

//Obsługa ikonek
override fun onOptionsItemSelected(item: MenuItem): Boolean {
val id: Int = item.itemId
if(id == R.id.action_settings) {
Expand Down
Loading

0 comments on commit 5236326

Please sign in to comment.