Skip to content

Custom Scopes

Filip edited this page Aug 11, 2019 · 5 revisions

Creating custom Scope

If you need some custom behaviour or you just want to understand how TmiK works you can create you own Scope. Each scope must inherit from abstract class TwitchScope or other context scopes. Context scopes (Global, Channel, User, UserState - ContextScope) give you access to listener helper functions (e.g. onUserJoin or onRoomState) relevant for given scope.

Class definition

class HelloScope(
    parent: TwitchScope,
    coroutineContext: CoroutineContext
) : GlobalContextScope(parent, coroutineContext) {
  // Implementation
}

Here we see that each scope needs to know its parent and have coroutineContext. The parent is used for chaining scopes where each element in the chain can alter messages going through it.
By inheriting from GlobalContextScope we gain access to all listener helper functions.

Override methods

override fun getTwitchFlow(): Flow<TwitchMessage> {
   return super.getTwitchFlow()
       .filter { it is TextMessage && it.message == "Hello" }
}

We can override two TwitchScope methods (sendRaw, getTwitchFlow). By overriding sendRaw we can intercept all messages sent from inside the scope, alter them or even ignore them. By overriding getTwitchFlow we can intercept all messages sent to the scope by altering message flow from super or even returning entirely different flow.
In the example above we let through only TextMessages with text "Hello" which means that only relevant listener inside our scope would be onMessage and we would get only messages which text would be "Hello". We would still be able to initialize other listeners (eg. onUserNotice) but those listener would never receive any message.

Builder function

@TwitchDsl
inline fun TwitchScope.hello(block: HelloScope.() -> Unit) =
    HelloScope(this, coroutineContext).apply(block)

To initialize the scope we need some builder function. The example above is the most simple builder function which takes TwitchScope from context it's called in and creates our HelloScope as its child. Than applies block function to it. The TwitchDsl annotation marks the function as DSL which means that you are not able to acces upper contexts directly. To learn more about Kotlin DSL, look in Kotlin documentation
Now we can call hello { } from any TwitchScope