peertube-live-streaming/app/src/main/java/fr/mobdev/peertubelive/manager/InstanceManager.kt

473 lines
19 KiB
Kotlin

package fr.mobdev.peertubelive.manager
import android.content.Context
import android.os.Bundle
import fr.mobdev.peertubelive.R
import fr.mobdev.peertubelive.objects.ChannelData
import fr.mobdev.peertubelive.objects.OAuthData
import fr.mobdev.peertubelive.objects.StreamData
import fr.mobdev.peertubelive.objects.StreamSettings
import org.json.JSONObject
import java.lang.Exception
import java.util.*
import kotlin.collections.ArrayList
import kotlin.collections.HashMap
object InstanceManager {
private val oauthManager : OAuthManager = OAuthManager()
private const val BASE_API_ENDPOINT: String = "/api/v1"
private const val REGISTER_CLIENT_ENDPOINT: String = "/oauth-clients/local"
private const val GET_USER_CLIENT_ENDPOINT: String = "/users/token"
private const val GET_USER_INFO_ENDPOINT: String = "/users/me"
private const val CREATE_LIVE_ENDPOINT: String = "/videos/live"
private const val GET_CATEGORY_ENDPOINT: String = "/videos/categories"
private const val GET_PRIVACY_ENDPOINT: String = "/videos/privacies"
private const val GET_LICENCE_ENDPOINT: String = "/videos/licences"
private const val GET_LANGUAGES_ENDPOINT: String = "/videos/languages"
private const val GET_VIDEOS: String = "/users/me/videos"
internal const val EXTRA_DATA: String = "EXTRA_DATA"
private const val CONTENT_TYPE: String = "CONTENT_TYPE"
private const val CONTENT_DATA: String = "CONTENT_DATA"
private const val VIDEO_CHANNEL: String = "videoChannels"
private const val CHANNEL_ID: String = "id"
private const val CHANNEL_NAME: String = "displayName"
private const val VIDEO: String = "video"
private const val UUID: String = "uuid"
private const val RTMP_URL: String = "rtmpUrl"
private const val STREAM_KEY: String = "streamKey"
fun registerAccount(context: Context, url: String, username: String, password: String, listener: InstanceListener) {
val registerUrl = url + BASE_API_ENDPOINT+ REGISTER_CLIENT_ENDPOINT
val internalListener: InstanceListener = object : InstanceListener {
override fun onSuccess(args: Bundle?) {
val oauthData: OAuthData? = args?.getParcelable(EXTRA_DATA)
oauthData?.baseUrl = url
if (oauthData != null)
getUserToken(context, url, username, password,oauthData, listener)
else
listener.onError(context.getString(R.string.unknwon_error))
}
override fun onError(error: String?) {
listener.onError(error)
}
override fun onUpdateOAuthData(oauthData: OAuthData) {
listener.onUpdateOAuthData(oauthData)
}
}
oauthManager.register(context,registerUrl,internalListener)
}
fun getUserToken(context: Context, url: String, username: String, password: String, oauthData: OAuthData, listener: InstanceListener) {
val userAccess = url + BASE_API_ENDPOINT + GET_USER_CLIENT_ENDPOINT
oauthManager.getUserToken(context, userAccess, username, password, oauthData, listener)
}
private fun refreshToken(context: Context, url: String, oauthData: OAuthData, listener: InstanceListener) {
val registerUrl = url + BASE_API_ENDPOINT+ GET_USER_CLIENT_ENDPOINT
oauthManager.refreshToken(context, registerUrl, oauthData, listener)
}
fun createLive(context: Context, url: String, oauthData: OAuthData, streamSettings: StreamSettings, listener: InstanceListener) {
if(oauthData.expires < Calendar.getInstance().timeInMillis) {
refreshToken(context,url,oauthData,object: InstanceListener {
override fun onSuccess(args: Bundle?) {
val oauth: OAuthData? = args?.getParcelable(InstanceManager.EXTRA_DATA)
if (oauth != null) {
DatabaseManager.updateCredentials(context,oauth)
listener.onUpdateOAuthData(oauth)
createLiveImpl(context, url,oauth,streamSettings,listener)
}
}
override fun onError(error: String?) {
listener.onError(error)
}
override fun onUpdateOAuthData(oauthData: OAuthData) {
listener.onUpdateOAuthData(oauthData)
}
})
} else {
createLiveImpl(context, url, oauthData,streamSettings,listener)
}
}
private fun getStreamKey(context: Context, url: String, oauthData: OAuthData, liveId: String, listener: InstanceListener) {
val liveInfo = "$url$BASE_API_ENDPOINT$CREATE_LIVE_ENDPOINT/$liveId"
val internalListener = object: InstanceListener {
override fun onSuccess(args: Bundle?) {
val response = args?.getString(EXTRA_DATA, null)
if (response == null) {
listener.onError(context.getString(R.string.unknwon_error))
return
}
val streamData = extractStreamData(response)
if (streamData == null) {
listener.onError(context.getString(R.string.json_error))
return
}
val results = Bundle()
results.putParcelable(EXTRA_DATA,streamData)
listener.onSuccess(results)
}
override fun onError(error: String?) {
listener.onError(error)
}
override fun onUpdateOAuthData(oauthData: OAuthData) {
listener.onUpdateOAuthData(oauthData)
}
}
oauthManager.get(context,liveInfo,oauthData,internalListener)
}
private fun createLiveImpl(context: Context, url: String, oauthData: OAuthData, streamSettings: StreamSettings, listener: InstanceListener) {
// val comments: Boolean, val download: Boolean, val nsfw: Boolean, val saveReplay: Boolean
val createLiveUrl = url + BASE_API_ENDPOINT + CREATE_LIVE_ENDPOINT
val data = Bundle()
val boundary = "45fcc22"
var formData: String = prepareFormData(boundary,"channelId",streamSettings.channel.toString(),false)
formData += prepareFormData(boundary,"name",streamSettings.title,false)
formData += prepareFormData(boundary,"privacy",streamSettings.privacy.toString(),false)
if(streamSettings.category != null)
formData += prepareFormData(boundary,"category",streamSettings.category.toString(),false)
if(streamSettings.language != null)
formData += prepareFormData(boundary,"language",streamSettings.language.toString(),false)
if(streamSettings.description != null)
formData += prepareFormData(boundary,"description",streamSettings.description.toString(),false)
if(streamSettings.licence != null)
formData += prepareFormData(boundary,"licence",streamSettings.licence.toString(),false)
formData += prepareFormData(boundary,"commentsEnabled",streamSettings.comments.toString(),false)
formData += prepareFormData(boundary,"nsfw",streamSettings.nsfw.toString(),false)
formData += prepareFormData(boundary,"downloadEnabled",streamSettings.download.toString(),false)
formData += prepareFormData(boundary,"saveReplay",streamSettings.saveReplay.toString(),true)
data.putString(CONTENT_TYPE,"multipart/form-data; boundary=$boundary")
data.putString(CONTENT_DATA,formData)
val internalListener = object: InstanceListener {
override fun onSuccess(args: Bundle?) {
val response = args?.getString(EXTRA_DATA, null)
if (response == null) {
listener.onError(context.getString(R.string.unknwon_error))
return
}
val liveId = extractLiveId(response)
if (liveId == null) {
listener.onError(context.getString(R.string.json_error))
return
}
getStreamKey(context,url,oauthData,liveId,listener)
}
override fun onError(error: String?) {
listener.onError(error)
}
override fun onUpdateOAuthData(oauthData: OAuthData) {
listener.onUpdateOAuthData(oauthData)
}
}
oauthManager.post(context,createLiveUrl,oauthData,data,internalListener)
}
fun getUserChannelList(context: Context, url: String, oauthData: OAuthData, listener: InstanceListener) {
if(oauthData.expires < Calendar.getInstance().timeInMillis) {
refreshToken(context,url,oauthData,object: InstanceListener {
override fun onSuccess(args: Bundle?) {
val oauth: OAuthData? = args?.getParcelable(EXTRA_DATA)
if (oauth != null) {
listener.onUpdateOAuthData(oauth)
DatabaseManager.updateCredentials(context,oauth)
getUserChannelListImpl(context, url,oauth,listener)
}
}
override fun onError(error: String?) {
listener.onError(error)
}
override fun onUpdateOAuthData(oauthData: OAuthData) {
listener.onUpdateOAuthData(oauthData)
}
})
} else {
getUserChannelListImpl(context, url, oauthData, listener)
}
}
private fun getUserChannelListImpl(context: Context, url: String, oauthData: OAuthData, listener: InstanceListener) {
val userInfoUrl: String = url + BASE_API_ENDPOINT + GET_USER_INFO_ENDPOINT
val internalListener : InstanceListener = object : InstanceListener {
override fun onSuccess(args: Bundle?) {
val response = args?.getString(EXTRA_DATA, null)
if (response == null) {
listener.onError(context.getString(R.string.unknwon_error))
return
}
val channelList = extractChannelData(response)
if (channelList == null) {
listener.onError(context.getString(R.string.json_error))
return
}
args.putParcelableArrayList(EXTRA_DATA, channelList)
listener.onSuccess(args)
}
override fun onError(error: String?) {
listener.onError(error)
}
override fun onUpdateOAuthData(oauthData: OAuthData) {
listener.onUpdateOAuthData(oauthData)
}
}
oauthManager.get(context,userInfoUrl,oauthData,internalListener)
}
fun getCategoryList(context: Context, url: String, listener: InstanceListener) {
val userInfoUrl: String = url + BASE_API_ENDPOINT + GET_CATEGORY_ENDPOINT
val internalListener : InstanceListener = object : InstanceListener {
override fun onSuccess(args: Bundle?) {
val response = args?.getString(EXTRA_DATA, null)
if (response == null) {
listener.onError(context.getString(R.string.unknwon_error))
return
}
val categoryList = extractMapData<Int>(response,0)
if (categoryList == null) {
listener.onError(context.getString(R.string.json_error))
return
}
categoryList[""]=0
args.putSerializable(EXTRA_DATA, categoryList)
listener.onSuccess(args)
}
override fun onError(error: String?) {
listener.onError(error)
}
override fun onUpdateOAuthData(oauthData: OAuthData) {
listener.onUpdateOAuthData(oauthData)
}
}
oauthManager.get(context,userInfoUrl,null,internalListener)
}
fun getPrivacyList(context: Context, url: String, listener: InstanceListener) {
val userInfoUrl: String = url + BASE_API_ENDPOINT + GET_PRIVACY_ENDPOINT
val internalListener : InstanceListener = object : InstanceListener {
override fun onSuccess(args: Bundle?) {
val response = args?.getString(EXTRA_DATA, null)
if (response == null) {
listener.onError(context.getString(R.string.unknwon_error))
return
}
val privacyList = extractMapData<Int>(response,0)
if (privacyList == null) {
listener.onError(context.getString(R.string.json_error))
return
}
args.putSerializable(EXTRA_DATA, privacyList)
listener.onSuccess(args)
}
override fun onError(error: String?) {
listener.onError(error)
}
override fun onUpdateOAuthData(oauthData: OAuthData) {
listener.onUpdateOAuthData(oauthData)
}
}
oauthManager.get(context,userInfoUrl,null,internalListener)
}
fun getLicencesList(context: Context, url: String, listener: InstanceListener) {
val userInfoUrl: String = url + BASE_API_ENDPOINT + GET_LICENCE_ENDPOINT
val internalListener : InstanceListener = object : InstanceListener {
override fun onSuccess(args: Bundle?) {
val response = args?.getString(EXTRA_DATA, null)
if (response == null) {
listener.onError(context.getString(R.string.unknwon_error))
return
}
val licencesList = extractMapData<Int>(response,0)
if (licencesList == null) {
listener.onError(context.getString(R.string.json_error))
return
}
licencesList[""]=0
args.putSerializable(EXTRA_DATA, licencesList)
listener.onSuccess(args)
}
override fun onError(error: String?) {
listener.onError(error)
}
override fun onUpdateOAuthData(oauthData: OAuthData) {
listener.onUpdateOAuthData(oauthData)
}
}
oauthManager.get(context,userInfoUrl,null,internalListener)
}
fun getLanguageList(context: Context, url: String, listener: InstanceListener) {
val userInfoUrl: String = url + BASE_API_ENDPOINT + GET_LANGUAGES_ENDPOINT
val internalListener : InstanceListener = object : InstanceListener {
override fun onSuccess(args: Bundle?) {
val response = args?.getString(EXTRA_DATA, null)
if (response == null) {
listener.onError(context.getString(R.string.unknwon_error))
return
}
val languageList = extractMapData<String>(response,"")
if (languageList == null) {
listener.onError(context.getString(R.string.json_error))
return
}
languageList[""]=""
args.putSerializable(EXTRA_DATA, languageList)
listener.onSuccess(args)
}
override fun onError(error: String?) {
listener.onError(error)
}
override fun onUpdateOAuthData(oauthData: OAuthData) {
listener.onUpdateOAuthData(oauthData)
}
}
oauthManager.get(context,userInfoUrl,null,internalListener)
}
private fun extractChannelData(response: String): ArrayList<ChannelData>? {
try {
val json = JSONObject(response)
if (json.has(VIDEO_CHANNEL)) {
val channelList: ArrayList<ChannelData> = ArrayList()
val channels = json.getJSONArray(VIDEO_CHANNEL)
for (i: Int in 0 until channels.length()) {
val channel = channels.getJSONObject(i)
if (channel.has(CHANNEL_NAME) && channel.has(CHANNEL_ID)) {
val name = channel.getString(CHANNEL_NAME)
val id = channel.getLong(CHANNEL_ID)
val channelData = ChannelData(id, name)
channelList.add(channelData)
} else {
return null
}
}
return channelList
} else {
return null
}
} catch (e: Exception) {
e.printStackTrace()
return null
}
}
private fun extractLiveId(response: String): String? {
try {
val json = JSONObject(response)
return if(json.has(VIDEO)) {
val video = json.getJSONObject(VIDEO)
if (video.has(UUID)) {
video.getString(UUID)
} else {
null
}
} else {
null
}
} catch (e: Exception) {
e.printStackTrace()
return null
}
}
private fun extractStreamData(response: String): StreamData? {
try {
val json = JSONObject(response)
return if (json.has(RTMP_URL) && json.has(STREAM_KEY)) {
val rtmp = json.getString(RTMP_URL)
val key = json.getString(STREAM_KEY)
StreamData(rtmp,key)
} else {
null
}
} catch (e: Exception) {
e.printStackTrace()
return null
}
}
private fun <T> extractMapData(response: String, type: T): HashMap<String,T>? {
return try {
val json = JSONObject(response)
val map = HashMap<String,T>()
for(key in json.keys()) {
if (type is Int)
map[json.getString(key)] = key.toInt() as T
else if (type is String)
map[json.getString(key)] = key as T
}
map
} catch (e: Exception) {
e.printStackTrace()
null
}
}
private fun prepareFormData(boundary: String, propertyName: String, property: String, lastData: Boolean): String {
val crlf = "\r\n"
var formData = "--$boundary$crlf"
formData+="Content-Disposition: form-data; name=\"$propertyName\"$crlf$crlf"
formData+="$property$crlf"
if(lastData) {
formData += "$crlf--$boundary--$crlf"
}
return formData
}
interface InstanceListener{
fun onSuccess(args: Bundle?)
fun onError(error: String?)
fun onUpdateOAuthData(oauthData: OAuthData)
}
}