All Downloads are FREE. Search and download functionalities are using the official Maven repository.

matedledstrip.animatedledstrip-android-client.1.0.source-code.AndroidAnimationSenderFactory.kt Maven / Gradle / Ivy

The newest version!
package animatedledstrip.androidclient

/*
 *  Copyright (c) 2019 AnimatedLEDStrip
 *
 *  Permission is hereby granted, free of charge, to any person obtaining a copy
 *  of this software and associated documentation files (the "Software"), to deal
 *  in the Software without restriction, including without limitation the rights
 *  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 *  copies of the Software, and to permit persons to whom the Software is
 *  furnished to do so, subject to the following conditions:
 *
 *  The above copyright notice and this permission notice shall be included in
 *  all copies or substantial portions of the Software.
 *
 *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 *  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 *  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 *  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 *  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 *  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 *  THE SOFTWARE.
 */

import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.Job
import kotlinx.coroutines.launch
import kotlinx.coroutines.newSingleThreadContext
import org.pmw.tinylog.Logger
import java.io.BufferedInputStream
import java.io.ObjectInputStream
import java.io.ObjectOutputStream
import java.net.InetSocketAddress
import java.net.Socket

object AndroidAnimationSenderFactory {
    var defaultSenderAndroid: AndroidAnimationSender? = null
        get() {
            return field ?: throw NullPointerException()
        }

    fun create(ipAddress: String = "10.0.0.254", port: Int = 5, connectAttemptLimit: Int = 5): AndroidAnimationSender {
        return AndroidAnimationSender(ipAddress, port, connectAttemptLimit)
    }

    class AndroidAnimationSender(val ipAddress: String, val port: Int, val connectAttemptLimit: Int) {
        private var socket: Socket = Socket()
        private var out: ObjectOutputStream? = null
        private var socIn: ObjectInputStream? = null
        private var disconnected = true
        private var connectionTries = 0
        private var action: ((Map<*, *>) -> Any?)? = null
        private var stopSocket = false
        private var started = false
        private var loopThread: Job? = null

        fun  setOnReceiveCallback(action: (Map<*, *>) -> R): AndroidAnimationSender {
            this.action = action
            return this
        }

        fun setAsDefaultSender(): AndroidAnimationSender {
            defaultSenderAndroid = this
            return this
        }

        fun start(): AndroidAnimationSender {
            if (!started) {
                loopThread = GlobalScope.launch(newSingleThreadContext("AndroidAnimationSender")) {
                    loop()
                }
                started = true
            }
            return this
        }

        fun end() {
            loopThread?.cancel()
        }

        private suspend fun loop() {
            while (!stopSocket) {
                connect()
                try {
                    out = ObjectOutputStream(socket.getOutputStream())
                    socIn = ObjectInputStream(BufferedInputStream(socket.getInputStream()))
                    var input: Map<*, *>
                    while (true) {
                        input = socIn!!.readObject() as Map<*, *>
                        Logger.debug("Received: $input")
                        action?.invoke(input)
                    }
                } catch (e: Exception) {
                    socket = Socket()
                    disconnected = true
                }
            }
        }

        private suspend fun connect() {
            try {
                socket.connect(InetSocketAddress(ipAddress, port), 5000)
                Logger.info("Connected to server at $ipAddress")
                disconnected = false
                connectionTries = 0
            } catch (e: Exception) {
                connectionTries++
                Logger.warn("Connection attempt $connectionTries: Server not found at $ipAddress: $e")
                Thread.sleep(10000)
                if (connectionTries <= connectAttemptLimit) {
                    socket = Socket()
                    connect()
                } else {
                    Logger.error("Could not locate server at $ipAddress after $connectionTries tries")
                }
            }
        }

        fun send(args: Map<*, *>) {
            try {
                out!!.writeObject(args)
            } catch (e: Exception) {
                Logger.error("Error sending animation: $e")
            }
        }

        fun isDisconnected() = disconnected

    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy