/* Ċ * ĠCopyright Ġ 2 0 1 9 ĠI vo ĠBer ger Ċ * Ċ * ĠLicensed Ġunder Ġthe ĠApache ĠLicense , ĠVersion Ġ 2 . 0 Ġ( the Ġ" License "); Ċ * Ġyou Ġmay Ġnot Ġuse Ġthis Ġfile Ġexcept Ġin Ġcompliance Ġwith Ġthe ĠLicense . Ċ * ĠYou Ġmay Ġobtain Ġa Ġcopy Ġof Ġthe ĠLicense Ġat Ċ * Ċ * Ġhttp :// www . apache . org / licenses / LICENSE - 2 . 0 Ċ * Ċ * ĠUnless Ġrequired Ġby Ġapplicable Ġlaw Ġor Ġagreed Ġto Ġin Ġwriting , Ġsoftware Ċ * Ġdistributed Ġunder Ġthe ĠLicense Ġis Ġdistributed Ġon Ġan Ġ" AS ĠIS " ĠBASIS , Ċ * ĠWITHOUT ĠWARRANTIES ĠOR ĠCONDITIONS ĠOF ĠANY ĠKIND , Ġeither Ġexpress Ġor Ġimplied . Ċ * ĠSee Ġthe ĠLicense Ġfor Ġthe Ġspecific Ġlanguage Ġgoverning Ġpermissions Ġand Ċ * Ġlimitations Ġunder Ġthe ĠLicense . Ċ */ Ċ package Ġcom . ivo ber ger . j music bot . client . model Ċ Ċ import Ġcom . ivo ber ger . j music bot . client . J Music Bot Ċ import Ġcom . ivo ber ger . j music bot . client . di . Server Module Ċ import Ġcom . ivo ber ger . j music bot . client . di . User Module Ċ import Ġcom . ivo ber ger . j music bot . client . logger Ċ import Ġcom . t inder . StateMachine Ċ import Ġkotlinx . coroutines . Experimental Cor outines Api Ċ import Ġkotlinx . coroutines . channels . send Blocking Ċ Ċ @ Experimental Cor outines Api Ċ internal Ġfun ĠJ Music Bot . make StateMachine (): ĠState Machine < State , ĠEvent , ĠSide Effect > Ġ= ĊĠĠĠ ĠState Machine . create Ġ{ ĊĠĠĠĠĠĠĠ ĠinitialState ( State . Disconnected ) ĊĠĠĠĠĠĠĠ Ġstate < State . Disconnected > Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġon < Event . Start Discovery > Ġ{ Ġtransition To ( State . Discover ing ) Ġ} ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġstate < State . Discover ing > Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġon < Event . Server Found > Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġtransition To ( State . Auth Required , ĠSide Effect . Start Server Session ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġon < Event . Disconnect > Ġ{ Ġtransition To ( State . Disconnected , ĠSide Effect . End Server Session ) Ġ} ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġstate < State . Auth Required > Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġon < Event . Authorize > Ġ{ Ġtransition To ( State . Connected , ĠSide Effect . Start User Session ) Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġon < Event . Disconnect > Ġ{ Ġtransition To ( State . Disconnected , ĠSide Effect . End Server Session ) Ġ} ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġstate < State . Connected > Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġon < Event . Auth Expired > Ġ{ Ġtransition To ( State . Auth Required , ĠSide Effect . End User Session ) Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġon < Event . Authorize > Ġ{ Ġtransition To ( State . Connected , ĠSide Effect . Start User Session ) Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġon < Event . Disconnect > Ġ{ Ġtransition To ( State . Disconnected , ĠSide Effect . End Server Session ) Ġ} ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġon Transition Ġ{ Ġtransition Ġ-> ĊĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġvalid Transition Ġ= Ġtransition Ġas ? ĠState Machine . Transition . Valid ĊĠĠĠĠĠĠĠĠĠĠĠ Ġvalid Transition ?. let Ġ{ Ġtrans Ġ-> ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġlogger . debug Ġ{ Ġ" State Ġtransition Ġfrom Ġ${ trans . from State } Ġto Ġ${ trans . to State } Ġby Ġ${ trans . event }" Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġwhen Ġ( trans . side Effect ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġis ĠSide Effect . Start Server Session Ġ-> Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġevent Ġ= Ġtrans . event Ġas ĠEvent . Server Found ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġm Server Session Ġ= ĠJ Music Bot . m Base Component . server Session ( event . server Module ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġm ServiceClient Ġ= Ġm Server Session !!. music Bot Service () ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġis ĠSide Effect . Start User Session Ġ-> Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġevent Ġ= Ġtrans . event Ġas ĠEvent . Authorize ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġm User Session Ġ= Ġm Server Session !!. user Session ( event . user Module ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġm ServiceClient Ġ= Ġm User Session !!. music Bot Service () ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġconnection Listeners . forEach Ġ{ Ġit . on Connection Re covered () Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠSide Effect . End User Session Ġ-> Ġend User Session () ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠSide Effect . End Server Session Ġ-> Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġend User Session () ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġm Server Session Ġ= Ġnull ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġm ServiceClient Ġ= Ġnull ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( trans . from State Ġis ĠState . Discover ing ) Ġreturn @ on Transition ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġevent Ġ= Ġtrans . event Ġas ĠEvent . Disconnect ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġconnection Listeners . forEach Ġ{ Ġit . on Connection Lost ( event . reason ) Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġstate Broadcast . send Blocking ( trans . to State ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġreturn @ on Transition ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġinvalid Transition Ġ= Ġtransition Ġas ? ĠState Machine . Transition . Invalid ĊĠĠĠĠĠĠĠĠĠĠĠ Ġinvalid Transition ?. let Ġ{ Ġlogger . debug Ġ{ Ġ" At tempted Ġcurrent State Ġtransition Ġfrom Ġ${ it . from State } Ġby Ġ${ it . event }" Ġ} Ġ} ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠ Ġ} Ċ Ċ @ Experimental Cor outines Api Ċ internal Ġfun ĠJ Music Bot . end User Session () Ġ{ ĊĠĠĠ Ġstop Player Updates () ĊĠĠĠ Ġstop Queue Updates () ĊĠĠĠ Ġm User Session Ġ= Ġnull ĊĠĠĠ Ġm ServiceClient Ġ= Ġm Server Session ?. music Bot Service () Ċ } Ċ Ċ /** Ċ Ġ* ĠPossible Ġstates Ġfor Ġthe Ġmusic Bot Service Ġbot Ġj music bot . j music bot . client Ġto Ġbe Ġin Ċ Ġ*/ Ċ sealed Ġclass ĠState Ġ{ ĊĠĠĠ Ġoverride Ġfun ĠtoString (): ĠString Ġ= Ġthis :: class . java . simple Name ĊĊĠĠĠ Ġ/** ĠClient Ġhas Ġno Ġserver Ġconnection Ġ*/ ĊĠĠĠ Ġobject ĠDis connected Ġ: ĠState () ĊĊĠĠĠ Ġ/** ĠClient Ġis Ġin Ġthe Ġtrying Ġto Ġfind Ġa Ġhost Ġ*/ ĊĠĠĠ Ġobject ĠDis cover ing Ġ: ĠState () ĊĊĠĠĠ Ġ/** ĠClient Ġhas Ġfound Ġa Ġserver Ġbut Ġneeds Ġlogin / new Ġauth Ġtoken Ġ*/ ĊĠĠĠ Ġobject ĠAuth Required Ġ: ĠState () ĊĊĠĠĠ Ġ/** ĠServer Ġconnection Ġand Ġauthentication Ġis Ġsuccessfully Ġestablished Ġ*/ ĊĠĠĠ Ġobject ĠConnected Ġ: ĠState () ĊĊĠĠĠ Ġval Ġis Disconnected ĊĠĠĠĠĠĠĠ Ġget () Ġ= Ġthis Ġ== ĠDis connected ĊĠĠĠ Ġval Ġis Discover ing ĊĠĠĠĠĠĠĠ Ġget () Ġ= Ġthis Ġ== ĠDis cover ing ĊĠĠĠ Ġval Ġauth Required ĊĠĠĠĠĠĠĠ Ġget () Ġ= Ġthis Ġ== ĠAuth Required ĊĠĠĠ Ġval Ġhas Server ĊĠĠĠĠĠĠĠ Ġget () Ġ= Ġauth Required ĊĠĠĠ Ġval Ġis Connected : ĠBoolean ĊĠĠĠĠĠĠĠ Ġget () Ġ= Ġthis Ġ== ĠConnected ĊĊĠĠĠ Ġ@ Throws ( IllegalStateException :: class ) ĊĠĠĠ Ġfun Ġconnection Check () Ġ{ ĊĠĠĠĠĠĠĠ Ġcheck ( isConnected ) Ġ{ Ġ" Client Ġnot Ġconnected " Ġ} ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġ@ Throws ( IllegalStateException :: class ) ĊĠĠĠ Ġfun Ġserver Check () Ġ{ ĊĠĠĠĠĠĠĠ Ġcheck ( has Server ) Ġ{ Ġ" Client Ġhas Ġno Ġserver " Ġ} ĊĠĠĠ Ġ} Ċ } Ċ Ċ sealed Ġclass ĠEvent Ġ{ ĊĠĠĠ Ġoverride Ġfun ĠtoString (): ĠString Ġ= Ġthis :: class . java . simple Name ĊĊĠĠĠ Ġobject ĠStart Discovery Ġ: ĠEvent () ĊĠĠĠ Ġclass ĠServer Found ( baseUrl : ĠString , Ġport : ĠInt ) Ġ: ĠEvent () Ġ{ ĊĠĠĠĠĠĠĠ Ġinternal Ġval Ġserver Module : ĠServer Module Ġ= ĠServer Module ( baseUrl , Ġport ) ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġclass ĠAuthor ize ( ĊĠĠĠĠĠĠĠ Ġuser : ĠUser , ĊĠĠĠĠĠĠĠ Ġauth Token : ĠAuth . Token ĊĠĠĠ Ġ) Ġ: ĠEvent () Ġ{ ĊĠĠĠĠĠĠĠ Ġinternal Ġval Ġuser Module : ĠUser Module ĊĊĠĠĠĠĠĠĠ Ġinit Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġuser . permissions Ġ= Ġauth Token . permissions ĊĠĠĠĠĠĠĠĠĠĠĠ Ġuser Module Ġ= ĠUser Module ( user , Ġauth Token ) ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġobject ĠAuth Expired Ġ: ĠEvent () ĊĠĠĠ Ġclass ĠDis connect ( val Ġreason : ĠException ? Ġ= Ġnull ) Ġ: ĠEvent () Ċ } Ċ Ċ sealed Ġclass ĠSide Effect Ġ{ ĊĠĠĠ Ġoverride Ġfun ĠtoString (): ĠString Ġ= Ġthis :: class . java . simple Name ĊĊĠĠĠ Ġobject ĠStart Server Session Ġ: ĠSide Effect () ĊĠĠĠ Ġobject ĠStart User Session Ġ: ĠSide Effect () ĊĠĠĠ Ġobject ĠEnd User Session Ġ: ĠSide Effect () ĊĠĠĠ Ġobject ĠEnd Server Session Ġ: ĠSide Effect () Ċ } Ċ