diff --git a/krontab/describing/krontabscheduler.html b/krontab/describing/krontabscheduler.html index cadc4e7..1406e26 100644 --- a/krontab/describing/krontabscheduler.html +++ b/krontab/describing/krontabscheduler.html @@ -1284,33 +1284,33 @@ See String format for more info about the crontab-line syntax

This way will be very useful for cases when you need to configure something via external configuration (from file on startup or via some parameter from requests, for example):

-
val schedule = "5 * * * *"
-val scheduler = buildSchedule(schedule)
-
-scheduler.asFlow().onEach {
-  // this block will be called every minute at 5 seconds
-}.launchIn(someCoroutineScope)
-
+
val schedule = "5 * * * *"
+val scheduler = buildSchedule(schedule)
+
+scheduler.asFlow().onEach {
+  // this block will be called every minute at 5 seconds
+}.launchIn(someCoroutineScope)
+

Lambda way

In case of usage builder (lets call it lambda way), you will be able to configure scheduler in more type-safe way:

-
val scheduler = buildSchedule {
-  seconds {
-    at(5)
-  }
-}
-
-scheduler.asFlow().onEach {
-  // this block will be called every minute at 5 seconds
-}.launchIn(someCoroutineScope)
-
+
val scheduler = buildSchedule {
+  seconds {
+    at(5)
+  }
+}
+
+scheduler.asFlow().onEach {
+  // this block will be called every minute at 5 seconds
+}.launchIn(someCoroutineScope)
+

Custom scheduler

You are always able to use your own realisation of scheduler. For example:

-
class RandomScheduler : KronScheduler {
-  override suspend fun next(relatively: DateTime): DateTime {
-    return relatively + DateTimeSpan(seconds = Random.nextInt() % 60)
-  }
-}
-
+
class RandomScheduler : KronScheduler {
+  override suspend fun next(relatively: DateTime): DateTime {
+    return relatively + DateTimeSpan(seconds = Random.nextInt() % 60)
+  }
+}
+

In the example above we have created RandomScheduler, which will return random next time in range 0-60 seconds since relatively argument.

diff --git a/krontab/describing/string-format.html b/krontab/describing/string-format.html index ef13269..4120a97 100644 --- a/krontab/describing/string-format.html +++ b/krontab/describing/string-format.html @@ -1403,22 +1403,22 @@

Example with almost same description:

-
/-------------------- (0-59) ············ Seconds
-| /------------------ (0-59) ············ Minutes
-| | /---------------- (0-23) ············ Hours
-| | | /-------------- (0-30) ············ Days of months
-| | | | /------------ (0-11) ············ Months
-| | | | | /---------- (optional, any int) Year
-| | | | | | /-------- (optional) ········ Timezone offset
-| | | | | | |  /----- (optional, 0-6) ··· Week days
-| | | | | | |  |  /-- (optional, 0-999) · Milliseconds (0 by default)
-* * * * * * 0o *w 0ms
-
+
/-------------------- (0-59) ············ Seconds
+| /------------------ (0-59) ············ Minutes
+| | /---------------- (0-23) ············ Hours
+| | | /-------------- (0-30) ············ Days of months
+| | | | /------------ (0-11) ············ Months
+| | | | | /---------- (optional, any int) Year
+| | | | | | /-------- (optional) ········ Timezone offset
+| | | | | | |  /----- (optional, 0-6) ··· Week days
+| | | | | | |  |  /-- (optional, 0-999) · Milliseconds (0 by default)
+* * * * * * 0o *w 0ms
+

Years, timezone, week days and milliseconds are optional settings. Next snippets are equal:

-
*/15 * * * *
-*/15 * * * * * // with year
-*/15 * * * * * 0ms // with year and milliseconds
-
+
*/15 * * * *
+*/15 * * * * * // with year
+*/15 * * * * * 0ms // with year and milliseconds
+

Supported syntax

Currently the library support next syntax for date/time elements:

Ranges

Ranges are working like common rangeTo (or ..) in kotlin:

-
0-5 * * * *
-
+
0-5 * * * *
+

In the example above scheduler will trigger every second from the beginning of the minute up to fifth second of minute.

Start/Step

Start/step is a little bit more complicated syntax. It means start from the first element, repeat triggering every second element. Examples:

-
5/15 * * * *
-
+
5/15 * * * *
+

Means that each minute starting from fifth second it will repeat triggering every fifteenth second: 5, 20, 35, 50.

Every

Every is more simple syntax and could be explained as a shortcut for 0/{int}. Example:

-
*/15 * * * *
-
+
*/15 * * * *
+

Means that each minute it will repeat triggering every fifteenth second: 0, 15, 30, 45.

Just at the time

The most simple syntax. It means, that scheduler will call triggering every time when element was reached:

-
15 * * * *
-
+
15 * * * *
+

Means that each minute scheduler will call triggering at the fifteenth second.

Listing

All the previous elements can be combined with listing. Lets just see several examples:

-
0,10 * * * *
-
+
0,10 * * * *
+

Will trigger every minute at the 0 and 10 seconds (see Just at the time)

-
0-5,10 * * * *
-
+
0-5,10 * * * *
+

Will trigger every minute from 0 to 5 seconds and at the 10 seconds (see Ranges)

Examples

Downloading with API extensions

Files (JVM/Android)

-
val bot: TelegramBot;
-val fileId: FileId;
-val outputFile: File;
-
-bot.downloadFile(fileId, outputFile)
-
+
val bot: TelegramBot;
+val fileId: FileId;
+val outputFile: File;
+
+bot.downloadFile(fileId, outputFile)
+

See downloadFile extension docs in the JVM tab to get more available options

There is also way with saving of data into temporal file. That will allow you to do with data whatever you want without high requirements to memory or network connection:

-
val bot: TelegramBot;
-val fileId: FileId;
-
-val tempFile: File = bot.downloadFileToTemp(fileId)
-
+
val bot: TelegramBot;
+val fileId: FileId;
+
+val tempFile: File = bot.downloadFileToTemp(fileId)
+

See downloadFileToTemp extension docs to get more available options

Byte read channel

-
val bot: TelegramBot;
-val fileId: FileId;
-
-val bytes: ByteReadChannelAllocator = bot.downloadFileStream(fileId)
-
+
val bot: TelegramBot;
+val fileId: FileId;
+
+val bytes: ByteReadChannelAllocator = bot.downloadFileStream(fileId)
+

See downloadFileStream extension docs to get more available options

Byte read channel allocator

-
val bot: TelegramBot;
-val fileId: FileId;
-
-val bytes: ByteReadChannelAllocator = bot.downloadFileStreamAllocator(fileId)
-
+
val bot: TelegramBot;
+val fileId: FileId;
+
+val bytes: ByteReadChannelAllocator = bot.downloadFileStreamAllocator(fileId)
+

See downloadFileStreamAllocator extension docs to get more available options

Byte arrays

-
val bot: TelegramBot;
-val fileId: FileId;
-
-val bytes: ByteArray = bot.downloadFile(fileId)
-
+
val bot: TelegramBot;
+val fileId: FileId;
+
+val bytes: ByteArray = bot.downloadFile(fileId)
+

See downloadFile extension docs to get more available options

Low level or how does it work?

You may download file with streams or with downloading into the memory first. On low level you should do several things. They are presented in next snippet:

-
val bot: TelegramBot;
-val fileId: FileId;
-
-val pathedFile: PathedFile = bot.execute(GetFile(fileId))
-
-val downloadedBytes: ByteArray = bot.execute(DownloadFile(pathedFile.filePath))
-
+
val bot: TelegramBot;
+val fileId: FileId;
+
+val pathedFile: PathedFile = bot.execute(GetFile(fileId))
+
+val downloadedBytes: ByteArray = bot.execute(DownloadFile(pathedFile.filePath))
+

In the snippet above we are getting file PathedFile by its FileId and use it to download file bytes into memory using DownloadFile request.

You may use almost the same way but with byte read channel allocator:

-
val bot: TelegramBot;
-val fileId: FileId;
-
-val pathedFile: PathedFile = bot.execute(GetFile(fileId))
-
-val channelAllocator: ByteReadChannelAllocator = bot.execute(DownloadFileStream(pathedFile.filePath))
-
-val byteReadChannel: ByteReadChannel = channelAllocator()
-
+
val bot: TelegramBot;
+val fileId: FileId;
+
+val pathedFile: PathedFile = bot.execute(GetFile(fileId))
+
+val channelAllocator: ByteReadChannelAllocator = bot.execute(DownloadFileStream(pathedFile.filePath))
+
+val byteReadChannel: ByteReadChannel = channelAllocator()
+

And then you may look into ByteReadChannel docs to get more info about what you can do with that.

Several useful links

@@ -1283,10 +1283,10 @@ Sending via file is accessible from all supported platforms, but there is small
  • Via asMultiparFile extension applicable to any ByteArray, ByteReadChannel, ByteReadChannelAllocator or File (on any platform)
  • In most cases, sending via files looks like in the next snippet:

    -
    val file: File;
    -
    -bot.sendDocument(chatId, file.asMultipartFile())
    -
    +
    val file: File;
    +
    +bot.sendDocument(chatId, file.asMultipartFile())
    +
    diff --git a/tgbotapi/logic/low-level-work-with-bots.html b/tgbotapi/logic/low-level-work-with-bots.html index 08c0060..9673d6b 100644 --- a/tgbotapi/logic/low-level-work-with-bots.html +++ b/tgbotapi/logic/low-level-work-with-bots.html @@ -1180,8 +1180,8 @@

    So, in most cases all your request calls with simplified api of this library (like bot.getMe()) will looks like bot.execute(GetMe). Result of these calls is defined in type of any request (for example, for GetMe request the result type is ExtendedBot). As a result, you can avoid any extension api (like special API extensions) and use low level request with full controlling of the whole logic flow.

    How to handle updates

    As was written above, it will require some request:

    -
    val updates = bot.execute(GetUpdates())
    -
    +
    val updates = bot.execute(GetUpdates())
    +

    Result type of GetUpdates request is Update. You may find inheritors of this interface in Update kdocs.

    What is next?

    As was said above, you may look into our API extensions in case you wish to use more high-level functions instead of bot.execute(SomeRequest()). Besides, it will be very useful to know more about updates retrieving.

    diff --git a/tgbotapi/logic/media-groups.html b/tgbotapi/logic/media-groups.html index cc2b236..7e48468 100644 --- a/tgbotapi/logic/media-groups.html +++ b/tgbotapi/logic/media-groups.html @@ -1234,21 +1234,21 @@ In tgbotapi there is no any additional handling of media groups by default and in case you will use simple bot.getUpdates, you will get the list of row updates and media groups will be included in this list as separated messages with MediaGroupPartContent. In that case you may use convertWithMediaGroupUpdates to be able to work with media groups as will be described below

    In case you are using standard long polling (one of alternatives is telegramBotWithBehaviourAndLongPolling) or webhooks updates will be converted uner the hood and as a result, you will take media groups as a content in one message:

    -
    telegramBotWithBehaviourAndLongPolling(
    -  "token"
    -) {
    -  onVisualGallery { // it: CommonMessage<MediaGroupContent<VisualMediaGroupPartContent>>
    -    it.content // MediaGroupContent<VisualMediaGroupPartContent>
    -    it.content.group // List<MediaGroupCollectionContent.PartWrapper<VisualMediaGroupPartContent>>
    -    it.content.group.forEach { // it: MediaGroupCollectionContent.PartWrapper<VisualMediaGroupPartContent>
    -      it.messageId // source message id for current media group part
    -      it.sourceMessage // source message for current media group part
    -      it.content // VisualMediaGroupPartContent
    -      println(it.content) // will print current content part info
    -    }
    -  }
    -}
    -
    +
    telegramBotWithBehaviourAndLongPolling(
    +  "token"
    +) {
    +  onVisualGallery { // it: CommonMessage<MediaGroupContent<VisualMediaGroupPartContent>>
    +    it.content // MediaGroupContent<VisualMediaGroupPartContent>
    +    it.content.group // List<MediaGroupCollectionContent.PartWrapper<VisualMediaGroupPartContent>>
    +    it.content.group.forEach { // it: MediaGroupCollectionContent.PartWrapper<VisualMediaGroupPartContent>
    +      it.messageId // source message id for current media group part
    +      it.sourceMessage // source message for current media group part
    +      it.content // VisualMediaGroupPartContent
    +      println(it.content) // will print current content part info
    +    }
    +  }
    +}
    +

    KDocs:

    Let’s look how it works with the factory above:

    -
    // Step 1 - create filter
    -val filter = flowsUpdatesFilter {
    -  // Step 2 - set up handling. In this case we will print any message from group or user in console
    -  messageFlow.onEach {
    -    println(it)
    -  }.launchIn(someCoroutineScope)
    -}
    -
    -// Step 3 - passing updates to filter
    -bot.getUpdates().forEach {
    -  filter.asUpdatesReceiver(it)
    -}
    -
    +
    // Step 1 - create filter
    +val filter = flowsUpdatesFilter {
    +  // Step 2 - set up handling. In this case we will print any message from group or user in console
    +  messageFlow.onEach {
    +    println(it)
    +  }.launchIn(someCoroutineScope)
    +}
    +
    +// Step 3 - passing updates to filter
    +bot.getUpdates().forEach {
    +  filter.asUpdatesReceiver(it)
    +}
    +

    Long polling

    Some example with long polling has been described above. But it is more useful to use some factories for it. In this page we will look for simple variant with TelegramBot#longPolling. So, with this function, your handling of updates will looks like:

    -
    val bot = telegramBot("TOKEN")
    -
    -bot.longPolling {
    -  messageFlow.onEach {
    -    println(it)
    -  }.launchIn(someCoroutineScope)
    -}.join()
    -
    +
    val bot = telegramBot("TOKEN")
    +
    +bot.longPolling {
    +  messageFlow.onEach {
    +    println(it)
    +  }.launchIn(someCoroutineScope)
    +}.join()
    +

    This example looks like the example above with three steps, but there are several important things here:

    longPolling

    longPolling is a simple way to start getting updates and work with bot:

    -
    val bot = telegramBot(token)
    -bot.longPolling(
    -  textMessages().subscribe(scope) { // here "scope" is a CoroutineScope
    -    println(it) // will be printed each update from chats with messages
    -  }
    -)
    -
    +
    val bot = telegramBot(token)
    +bot.longPolling(
    +  textMessages().subscribe(scope) { // here "scope" is a CoroutineScope
    +    println(it) // will be printed each update from chats with messages
    +  }
    +)
    +

    startGettingOfUpdatesByLongPolling

    The main aim of startGettingOfUpdatesByLongPolling extension was to provide more simple way to get updates in automatic mode:

    -
    val bot = telegramBot(token)
    -bot.startGettingOfUpdatesByLongPolling(
    -  {
    -    println(it) // will be printed each update from chats with messages
    -  }
    -)
    -
    +
    val bot = telegramBot(token)
    +bot.startGettingOfUpdatesByLongPolling(
    +  {
    +    println(it) // will be printed each update from chats with messages
    +  }
    +)
    +

    The other way is to use the most basic startGettingOfUpdatesByLongPolling extension:

    -
    val bot = telegramBot(token)
    -bot.startGettingOfUpdatesByLongPolling {
    -  println(it) // will be printed each update
    -}
    -
    +
    val bot = telegramBot(token)
    +bot.startGettingOfUpdatesByLongPolling {
    +  println(it) // will be printed each update
    +}
    +

    See also