add writable parts of server and client
This commit is contained in:
parent
a3cc3e8537
commit
3e7a2c1f0d
@ -32,6 +32,7 @@ dependencies {
|
||||
api project(":ClientServerCommon")
|
||||
|
||||
api "io.ktor:ktor-client:$ktor_version"
|
||||
api "io.ktor:ktor-client-websockets:$ktor_version"
|
||||
}
|
||||
|
||||
compileKotlin {
|
||||
|
@ -0,0 +1,40 @@
|
||||
package com.insanusmokrassar.postssystem.core.client
|
||||
|
||||
import io.ktor.client.HttpClient
|
||||
import io.ktor.client.features.websocket.ws
|
||||
import io.ktor.http.HttpMethod
|
||||
import io.ktor.http.cio.websocket.Frame
|
||||
import io.ktor.http.cio.websocket.readText
|
||||
import kotlinx.coroutines.InternalCoroutinesApi
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.FlowCollector
|
||||
|
||||
class EventFlow<T>(
|
||||
private val client: HttpClient,
|
||||
private val host: String,
|
||||
private val port: Int,
|
||||
private val path: String,
|
||||
private val dataConverter: suspend (String) -> T
|
||||
) : Flow<T> {
|
||||
@InternalCoroutinesApi
|
||||
override suspend fun collect(collector: FlowCollector<T>) {
|
||||
client.ws(
|
||||
method = HttpMethod.Get,
|
||||
host = host,
|
||||
port = port,
|
||||
path = path
|
||||
) {
|
||||
var frame = incoming.receiveOrClosed()
|
||||
while (!frame.isClosed) {
|
||||
val frameVal = frame.value
|
||||
when (frameVal) {
|
||||
is Frame.Text -> {
|
||||
collector.emit(
|
||||
dataConverter(frameVal.readText())
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,28 +1,46 @@
|
||||
package com.insanusmokrassar.postssystem.core.client
|
||||
|
||||
import com.insanusmokrassar.postssystem.core.api.WritePostsAPI
|
||||
import com.insanusmokrassar.postssystem.core.clientserver.common.*
|
||||
import com.insanusmokrassar.postssystem.core.clientserver.common.models.UpdatePostRequest
|
||||
import com.insanusmokrassar.postssystem.core.post.*
|
||||
import io.ktor.client.HttpClient
|
||||
import io.ktor.client.request.post
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.serialization.json.Json
|
||||
|
||||
class WritableHttpPostsAPI(
|
||||
|
||||
private val hostUrl: String,
|
||||
private val port: Int,
|
||||
private val client: HttpClient
|
||||
) : WritePostsAPI {
|
||||
override val postCreatedFlow: Flow<Post>
|
||||
get() = TODO("not implemented") //To change initializer of created properties use File | Settings | File Templates.
|
||||
override val postDeletedFlow: Flow<Post>
|
||||
get() = TODO("not implemented") //To change initializer of created properties use File | Settings | File Templates.
|
||||
override val postUpdatedFlow: Flow<Post>
|
||||
get() = TODO("not implemented") //To change initializer of created properties use File | Settings | File Templates.
|
||||
|
||||
override suspend fun createPost(content: PostContents): Post? {
|
||||
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
|
||||
private inline fun postEventFlow(url: String) = EventFlow(
|
||||
client,
|
||||
hostUrl,
|
||||
port,
|
||||
"/$url"
|
||||
) {
|
||||
Json.plain.parse(SimplePost.serializer(), it)
|
||||
}
|
||||
|
||||
override suspend fun deletePost(id: PostId): Boolean {
|
||||
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
|
||||
override val postCreatedFlow: Flow<Post> = postEventFlow(eventPostsCreatedAddress)
|
||||
override val postDeletedFlow: Flow<Post> = postEventFlow(eventPostsDeletedAddress)
|
||||
override val postUpdatedFlow: Flow<Post> = postEventFlow(eventPostsUpdatedAddress)
|
||||
|
||||
override suspend fun createPost(content: PostContents): Post? = client.post<SimplePost>(
|
||||
createPostAddress
|
||||
) {
|
||||
body = content
|
||||
}
|
||||
|
||||
override suspend fun updatePostContent(postId: PostId, content: PostContents): Boolean {
|
||||
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
|
||||
override suspend fun deletePost(id: PostId): Boolean = client.post(deletePostAddress) {
|
||||
body = id
|
||||
}
|
||||
|
||||
override suspend fun updatePostContent(
|
||||
postId: PostId,
|
||||
content: PostContents
|
||||
): Boolean = client.post(createPostAddress) {
|
||||
body = UpdatePostRequest(postId, content)
|
||||
}
|
||||
}
|
@ -5,6 +5,14 @@ const val getPostsByContentIdAddress = "core/posts/get/content_id"
|
||||
const val getPostsByDatesAddress = "core/posts/get/dates"
|
||||
const val getPostsByPaginationAddress = "core/posts/get/pagination"
|
||||
|
||||
const val eventPostsCreatedAddress = "core/posts/event/created"
|
||||
const val eventPostsUpdatedAddress = "core/posts/event/updated"
|
||||
const val eventPostsDeletedAddress = "core/posts/event/deleted"
|
||||
|
||||
const val createPostAddress = "core/posts/create"
|
||||
const val updatePostAddress = "core/posts/update"
|
||||
const val deletePostAddress = "core/posts/delete"
|
||||
|
||||
//class ReadPaths(
|
||||
// val baseAddress: String
|
||||
//) {
|
||||
|
@ -0,0 +1,11 @@
|
||||
package com.insanusmokrassar.postssystem.core.clientserver.common.models
|
||||
|
||||
import com.insanusmokrassar.postssystem.core.post.PostContents
|
||||
import com.insanusmokrassar.postssystem.core.post.PostId
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
data class UpdatePostRequest(
|
||||
val id: PostId,
|
||||
val content: PostContents
|
||||
)
|
@ -1,7 +1,5 @@
|
||||
package com.insanusmokrassar.postssystem.core.content
|
||||
|
||||
import org.joda.time.DateTime
|
||||
|
||||
typealias ContentId = String
|
||||
|
||||
interface Content {
|
||||
|
@ -33,6 +33,7 @@ dependencies {
|
||||
|
||||
api "io.ktor:ktor-server:$ktor_version"
|
||||
api "io.ktor:ktor-server-core:$ktor_version"
|
||||
api "io.ktor:ktor-websockets:$ktor_version"
|
||||
}
|
||||
|
||||
compileKotlin {
|
||||
|
@ -8,8 +8,10 @@ import io.ktor.http.ContentType
|
||||
import io.ktor.http.HttpStatusCode
|
||||
import io.ktor.response.respond
|
||||
import io.ktor.response.respondText
|
||||
import kotlinx.serialization.InternalSerializationApi
|
||||
import kotlinx.serialization.KSerializer
|
||||
import kotlinx.serialization.internal.ArrayListSerializer
|
||||
import kotlinx.serialization.internal.NullableSerializer
|
||||
import kotlinx.serialization.json.Json
|
||||
|
||||
|
||||
@ -27,11 +29,12 @@ internal val Post.asSimplePost
|
||||
else -> SimplePost(id, content, meta)
|
||||
}
|
||||
|
||||
internal suspend fun <T> ApplicationCall.answer(
|
||||
@InternalSerializationApi
|
||||
internal suspend fun <T : Any> ApplicationCall.answer(
|
||||
serializer: KSerializer<T>,
|
||||
answerObject: T
|
||||
answerObject: T?
|
||||
) = respondText(ContentType.Application.Json) {
|
||||
Json.plain.stringify(serializer, answerObject)
|
||||
Json.plain.stringify(NullableSerializer(serializer), answerObject)
|
||||
}
|
||||
|
||||
internal suspend fun ApplicationCall.answerBadRequest(
|
||||
|
@ -0,0 +1,54 @@
|
||||
package com.insanusmokrassar.postssystem.core.server
|
||||
|
||||
import com.insanusmokrassar.postssystem.core.api.WritePostsAPI
|
||||
import com.insanusmokrassar.postssystem.core.clientserver.common.*
|
||||
import com.insanusmokrassar.postssystem.core.clientserver.common.models.UpdatePostRequest
|
||||
import com.insanusmokrassar.postssystem.core.post.*
|
||||
import io.ktor.application.call
|
||||
import io.ktor.http.cio.websocket.Frame
|
||||
import io.ktor.request.receiveOrNull
|
||||
import io.ktor.routing.Route
|
||||
import io.ktor.routing.post
|
||||
import io.ktor.websocket.webSocket
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.collect
|
||||
import kotlinx.serialization.InternalSerializationApi
|
||||
import kotlinx.serialization.internal.BooleanSerializer
|
||||
import kotlinx.serialization.json.Json
|
||||
|
||||
private inline fun Route.createWebsocket(path: String, flow: Flow<Post>) {
|
||||
webSocket("/$path") {
|
||||
flow.collect {
|
||||
val simplePost = it.asSimplePost
|
||||
outgoing.send(Frame.Text(Json.plain.stringify(SimplePost.serializer(), simplePost)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@InternalSerializationApi
|
||||
fun Route.includePostsCoreWriteModules(
|
||||
writePostsAPI: WritePostsAPI
|
||||
) {
|
||||
createWebsocket(eventPostsCreatedAddress, writePostsAPI.postCreatedFlow)
|
||||
createWebsocket(eventPostsDeletedAddress, writePostsAPI.postDeletedFlow)
|
||||
createWebsocket(eventPostsUpdatedAddress, writePostsAPI.postUpdatedFlow)
|
||||
|
||||
post(createPostAddress) {
|
||||
call.receiveOrNull<PostContents>() ?.also { contents ->
|
||||
val post = writePostsAPI.createPost(contents)
|
||||
|
||||
call.answer(SimplePost.serializer(), post ?.asSimplePost)
|
||||
} ?: call.answerBadRequest("Contents (List of Content)")
|
||||
}
|
||||
|
||||
post(deletePostAddress) {
|
||||
call.receiveOrNull<PostId>() ?.also { postId ->
|
||||
call.answer(BooleanSerializer, writePostsAPI.deletePost(postId))
|
||||
} ?: call.answerBadRequest("Post Id (String)")
|
||||
}
|
||||
post(deletePostAddress) {
|
||||
call.receiveOrNull<UpdatePostRequest>() ?.also { (postId, contents) ->
|
||||
call.answer(BooleanSerializer, writePostsAPI.updatePostContent(postId, contents))
|
||||
} ?: call.answerBadRequest("Post Id (String)")
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user