├── .github └── workflows │ └── main.yml ├── .smalltalk.ston ├── .squot ├── README.md ├── img ├── architecture.svg ├── banner.svg ├── screencast.gif └── screenshot1.png ├── scripts └── preLoading.st └── src ├── BaselineOfTelegramSmalltalkBot.package ├── .filetree ├── .squot-contents ├── BaselineOfTelegramSmalltalkBot.class │ ├── README.md │ ├── instance │ │ ├── baseline..st │ │ ├── depChangeset..st │ │ ├── depMergeVersion..st │ │ ├── installPreviewDependencies.st │ │ └── projectClass.st │ ├── methodProperties.json │ └── properties.json ├── monticello.meta │ ├── categories.st │ └── initializers.st └── properties.json ├── TelegramSmalltalkBot-Core.package ├── .filetree ├── .squot-contents ├── Collection.extension │ ├── instance │ │ └── asTelegramSmalltalkBotMessageFor..st │ ├── methodProperties.json │ └── properties.json ├── CompiledCode.extension │ ├── instance │ │ └── asTelegramSmalltalkBotMessageFor..st │ ├── methodProperties.json │ └── properties.json ├── Dictionary.extension │ ├── instance │ │ └── asTelegramSmalltalkBotMessageFor..st │ ├── methodProperties.json │ └── properties.json ├── Object.extension │ ├── instance │ │ └── asTelegramSmalltalkBotMessageFor..st │ ├── methodProperties.json │ └── properties.json ├── String.extension │ ├── instance │ │ ├── asTelegramSmalltalkBotMessageFor..st │ │ └── tbWithoutLineEndings.st │ ├── methodProperties.json │ └── properties.json ├── TelegramSmalltalkBot.class │ ├── README.md │ ├── class │ │ ├── repositoryStub.st │ │ ├── repositoryUrl.st │ │ ├── repositoryUrlAboutIsolation.st │ │ └── secrets.st │ ├── instance │ │ ├── answerCommand.message..st │ │ ├── answerDo..st │ │ ├── answerInspect..st │ │ ├── answerPrint..st │ │ ├── doHelp..st │ │ ├── doReset..st │ │ ├── doStart..st │ │ ├── editMessage.changeTo..st │ │ ├── errorText..st │ │ ├── exceptionText..st │ │ ├── generateAnswerTo..st │ │ ├── generateCodeExample.st │ │ ├── handleCommand.message..st │ │ ├── helpStrings.st │ │ ├── initialize.st │ │ ├── isDebugging..st │ │ ├── isDebugging.st │ │ ├── logErrorsDuring.replyTo..st │ │ ├── messageBlocked.withError..st │ │ ├── messageEdited..st │ │ ├── messageReceived..st │ │ ├── messageWith..st │ │ ├── messageWithCollection..st │ │ ├── messageWithDictionary..st │ │ ├── messageWithErrorText..st │ │ ├── messageWithExceptionText..st │ │ ├── messageWithItems.caption..st │ │ ├── messageWithObject..st │ │ ├── messageWithUserText..st │ │ ├── processMessage.andDo..st │ │ ├── processMessage.andDo.ifError..st │ │ ├── removeSession.ifAbsent..st │ │ ├── replyMessage.withHtml..st │ │ ├── replyMessage.withHtmls.beforeSendDo..st │ │ └── sessionFor..st │ ├── methodProperties.json │ └── properties.json ├── TelegramSmalltalkSession.class │ ├── README.md │ ├── instance │ │ ├── basicRecordAnswer..st │ │ ├── basicRecordResult.forMessage..st │ │ ├── bindingOf..st │ │ ├── doSafely.ifError..st │ │ ├── doSafely.on.do.useSandbox..st │ │ ├── evaluate.for.ifError..st │ │ ├── initialize.st │ │ ├── isolationEnabled..st │ │ ├── isolationEnabled.st │ │ ├── maximumMemorySize.st │ │ ├── maximumRecordSize.st │ │ ├── mustDeclareVariables.st │ │ ├── notify.at.in..st │ │ ├── obfuscateSecret..st │ │ ├── pinRecord.to..st │ │ ├── processMessage.ifError..st │ │ ├── receiverFor..st │ │ ├── record.fromAnswer.bot..st │ │ ├── recordedAnswerTo.ifAbsent..st │ │ ├── reset.st │ │ ├── scheduleRecord.fromAnswer..st │ │ ├── secrets.st │ │ ├── tidyUpRecords..st │ │ └── wantsInteractiveErrorCorrection.st │ ├── methodProperties.json │ └── properties.json ├── Text.extension │ ├── instance │ │ └── asTelegramSmalltalkBotMessageFor..st │ ├── methodProperties.json │ └── properties.json ├── monticello.meta │ ├── categories.st │ └── initializers.st └── properties.json └── TelegramSmalltalkBot-Tests.package ├── .filetree ├── .squot-contents ├── TelegramSmalltalkBotTest.class ├── README.md ├── instance │ ├── askBot..st │ ├── botSession.st │ ├── clientChatId.st │ ├── editMessage.text..st │ ├── makeChat.st │ ├── makeMessageFrom..st │ ├── nextMessageId.st │ ├── receiveBotMessagesDuring..st │ ├── receiveEditedBotMessagesDuring..st │ ├── sendMessage..st │ ├── setUp.st │ ├── shouldBotAsked.answer..st │ ├── shouldBotAsked.answerSatisfy..st │ ├── shouldBotAsked.answersSatisfy..st │ ├── someNumber.st │ ├── someString.st │ ├── tearDown.st │ ├── testAnimation.st │ ├── testDialog.st │ ├── testDo.st │ ├── testEditMessage.st │ ├── testForm.st │ ├── testHelp.st │ ├── testInspect.st │ ├── testInternalError.st │ ├── testPrint.st │ ├── testRuntimeError.st │ ├── testSimple.st │ ├── testSound.st │ ├── testStart.st │ ├── testSyntaxError.st │ ├── testText.st │ └── testVariables.st ├── methodProperties.json └── properties.json ├── monticello.meta ├── categories.st └── initializers.st └── properties.json /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | name: smalltalkCI 2 | 3 | on: 4 | push: 5 | schedule: 6 | - cron: "0 0 * * 1" 7 | 8 | jobs: 9 | build: 10 | runs-on: ubuntu-latest 11 | name: ${{ matrix.smalltalk }} on ${{ matrix.os }} 12 | steps: 13 | - uses: actions/checkout@v2 14 | - uses: hpi-swa/setup-smalltalkCI@v1 15 | id: smalltalkci 16 | with: 17 | smalltalk-image: Squeak64-Trunk 18 | - name: Run test suite 19 | shell: bash 20 | run: smalltalkci -s ${{ steps.smalltalkci.outputs.smalltalk-image }} 21 | timeout-minutes: 15 22 | env: 23 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 24 | # GITHUB_TOKEN lacks permission to read other repositories that are depended in the baseline. 25 | GH_ACCESS_TOKEN: ${{ secrets.GH_ACCESS_TOKEN }} 26 | - name: Send email on failure 27 | if: ${{ github.event_name == 'schedule' && failure() }} 28 | uses: dawidd6/action-send-mail@v2 29 | with: 30 | server_address: ${{ secrets.SMTP_SERVER }} 31 | server_port: ${{ secrets.SMTP_PORT }} 32 | username: ${{ secrets.SMTP_USERNAME }} 33 | password: ${{ secrets.SMTP_PASSWORD }} 34 | subject: GitHub Actions failed for ${{ github.repository }} 35 | body: Build job of ${{ github.repository }} failed! See https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }} for more information. 36 | to: ${{ secrets.MAIL_RECEIVER }} 37 | from: GitHub Actions 38 | -------------------------------------------------------------------------------- /.smalltalk.ston: -------------------------------------------------------------------------------- 1 | SmalltalkCISpec { 2 | #preLoading : 'scripts/preLoading.st', 3 | #loading : [ 4 | SCIMetacelloLoadSpec { 5 | #baseline : 'TelegramSmalltalkBot', 6 | #directory : 'src', 7 | #platforms : [ #squeak ], 8 | #load : [ 'TelegramSmalltalkBot-Tests' ] 9 | } 10 | ], 11 | #testing : { 12 | #packages : [ 'TelegramSmalltalkBot-Tests' ], 13 | #coverage : { 14 | #packages : [ 'TelegramSmalltalkBot-Core' ] 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /.squot: -------------------------------------------------------------------------------- 1 | OrderedDictionary { 2 | 'src\/TelegramSmalltalkBot-Core.package' : #SquotCypressCodeSerializer, 3 | 'src\/TelegramSmalltalkBot-Tests.package' : #SquotCypressCodeSerializer, 4 | 'src\/BaselineOfTelegramSmalltalkBot.package' : #SquotCypressCodeSerializer 5 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # TelegramSmalltalkBot 2 | 3 | [![Actions Status](https://github.com/LinqLover/TelegramSmalltalkBot/workflows/smalltalkCI/badge.svg)](https://github.com/LinqLover/TelegramSmalltalkBot/actions) 4 | [![Coverage Status](https://coveralls.io/repos/github/LinqLover/TelegramSmalltalkBot/badge.svg)](https://coveralls.io/github/LinqLover/TelegramSmalltalkBot) 5 | [![Chat now](https://img.shields.io/badge/chat%20now-%40SqueakSmalltalkBot-0088cc)](https://t.me/SqueakSmalltalkBot) 6 | 7 | A Telegram bot that connects you to a remote [Squeak/Smalltalk](https://squeak.org/) image and allows you to explore it by sending Smalltalk expressions to the bot. 8 | Implemented using the [TelegramBot framework](https://github.com/LinqLover/TelegramBot) and [SimulationStudio](https://github.com/LinqLover/SimulationStudio) for sandboxed execution. 9 | 10 |

11 | Screenshot of a Telegram chat with the following messages sent to the bot: `Smalltalk version`, `3 + 4 * 6`, and `Display := Form extent: 600 asPoint depth: 32. Pen new mandala: 30. Display`. 12 | Screencast of a Telegram chat. 13 |

14 | 15 | Currently available features include, but are not limited to: 16 | 17 | - Evaluate arbitrary Smalltalk expressions 18 | - Multi-user object memory with isolated execution to rule out global side effects in the image 19 | - Select the receiver context (`self`) for your expressions by replying to a specific previous message of the bot 20 | - Edit your messages and answers from the bot will be updated as well 21 | - Multi-media representations of various Smalltalk objects such as `Text`, `Form`, `AnimatedImageMorph`, `AbstractSound`, and others 22 | - Bot commands to create different views of expression results such as `/do`, `/print`, and `inspect` 23 | 24 | To learn more about all capabilities, just [try it out](#try-it-out) and send the `/help` command. 25 | 26 | There is also a [screencast available on YouTube](https://youtu.be/HZCeThLqQmg). 27 | 28 | ## Try it out! 29 | 30 | An instance of the bot is live under [@SqueakSmalltalkBot](https://t.me/SqueakSmalltalkBot). 31 | Just send it a message and say hello! 32 | 33 | @SqueakSmalltalkBot 34 | 35 | If you experience any problems, please [create an issue](https://github.com/LinqLover/TelegramSmalltalkBot/issues/new/choose). 36 | 37 | ## Self-Hosting the Bot 38 | 39 | 1. Install the latest Trunk updates in your image, then evaluate the following in a Workspace: 40 | 41 | ```smalltalk 42 | Metacello new 43 | baseline: 'TelegramSmalltalkBot'; 44 | githubUser: 'LinqLover' project: 'TelegramSmalltalkBot' path: 'src'; 45 | load. 46 | ``` 47 | 48 | 2. Chat with [@BotFather](https://t.me/BotFather) to register your very own bot. 49 | He will send you a secret bot token. 50 | 51 | 3. To start a bot instance, do something like: 52 | 53 | ```smalltalk 54 | bot := TelegramSmalltalkBot withToken: ''. 55 | bot spawnNewProcess. 56 | ``` 57 | 58 | 4. Send a message to your bot and enjoy! 59 | 60 | 5. If you do not want that everyone from all over the world has access to your bot, you can define an allow-list of chat IDs and provide it via the `TBTestBotChatIds` global variable (experimental): 61 | 62 | ```smalltalk 63 | Smalltalk at: #TBTestBotChatIds put: #(). 64 | ``` 65 | 66 | You can find out your own chat ID by browsing the sessions object of your running bot instance using an object explorer, or by inspecting the result of `bot peekUpdates` after sending a message to the bot. 67 | 68 | For more information on how to run the bot, read the docs of the [TelegramBot framework](https://github.com/LinqLover/TelegramBot#usage). 69 | 70 | Configuration of the bot (e.g. to turn off isolation and quota mechanisms) is currently only supported by editing the source code, though it contains some applicable hooks such as `TelegramSmalltalkSession >> #isolationEnabled`. 71 | If you miss a certain configuration hook or extension point, please create an issue or a pull request. 72 | 73 | For more information on the architecture and set-up of this bot, please refer to [this overview](https://linqlover.github.io/LinqLover/slides/SqueakEv21W%20TelegramBot.pdf#page=2). 74 | 75 | There is also an inofficial setup tutorial available that was written by [@cstes](https://github.com/cstes): [Running a TelegramSmalltalkBot in a minimal zone on Oracle Solaris 11](https://master.dl.sourceforge.net/project/solaris-squeak/tbot21.pdf) ([mirror](https://web.archive.org/web/20231128210657/https://master.dl.sourceforge.net/project/solaris-squeak/tbot21.pdf?viasf=1)) 76 | 77 | ## Development 78 | 79 | Version control is run using [Squot](https://github.com/hpi-swa/Squot). 80 | Your contribution is welcome! 81 | I'm always happy about bug reports, new feature proposals, or even pull requests ... :-) 82 | 83 | Carpe Squeak! 84 | -------------------------------------------------------------------------------- /img/banner.svg: -------------------------------------------------------------------------------- 1 | @SqueakSmalltalkBot -------------------------------------------------------------------------------- /img/screencast.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LinqLover/TelegramSmalltalkBot/9ffd71a4b40aa175aa4e1ae33e42952c84598f9a/img/screencast.gif -------------------------------------------------------------------------------- /img/screenshot1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LinqLover/TelegramSmalltalkBot/9ffd71a4b40aa175aa4e1ae33e42952c84598f9a/img/screenshot1.png -------------------------------------------------------------------------------- /scripts/preLoading.st: -------------------------------------------------------------------------------- 1 | "Workaround for https://github.com/hpi-swa/smalltalkCI/pull/485 and https://github.com/Metacello/metacello/issues/524" 2 | SCIMetacelloLoadSpec updateMetacello. 3 | 4 | "Actual credentials configuration" 5 | MCFetchGithubRepository sitePassword: (SmalltalkCI getEnv: 'GH_ACCESS_TOKEN'). 6 | -------------------------------------------------------------------------------- /src/BaselineOfTelegramSmalltalkBot.package/.filetree: -------------------------------------------------------------------------------- 1 | { 2 | "noMethodMetaData" : true, 3 | "separateMethodMetaAndSource" : false, 4 | "useCypressPropertiesFile" : true } 5 | -------------------------------------------------------------------------------- /src/BaselineOfTelegramSmalltalkBot.package/.squot-contents: -------------------------------------------------------------------------------- 1 | SquotTrackedObjectMetadata { 2 | #objectClassName : #PackageInfo, 3 | #objectsReplacedByNames : true, 4 | #serializer : #SquotCypressCodeSerializer 5 | } -------------------------------------------------------------------------------- /src/BaselineOfTelegramSmalltalkBot.package/BaselineOfTelegramSmalltalkBot.class/README.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LinqLover/TelegramSmalltalkBot/9ffd71a4b40aa175aa4e1ae33e42952c84598f9a/src/BaselineOfTelegramSmalltalkBot.package/BaselineOfTelegramSmalltalkBot.class/README.md -------------------------------------------------------------------------------- /src/BaselineOfTelegramSmalltalkBot.package/BaselineOfTelegramSmalltalkBot.class/instance/baseline..st: -------------------------------------------------------------------------------- 1 | baseline 2 | baseline: spec 3 | 4 | 5 | spec for: #common do: [ 6 | "dependencies" 7 | spec 8 | baseline: 'TelegramBot' with: [ 9 | spec 10 | repository: 'github://LinqLover/TelegramBot/src'; 11 | loads: #minimal]; 12 | baseline: 'SimulationStudio' with: [ 13 | spec 14 | repository: 'github://LinqLover/SimulationStudio/packages'; 15 | loads: 'SimulationStudio-Sandbox']; 16 | package: 'JSON' with: [ 17 | spec repository: 'https://www.squeaksource.com/PostgresV3']. 18 | 19 | "packages" 20 | spec 21 | package: 'TelegramSmalltalkBot-Core' with: [ 22 | spec requires: #('TelegramBot' 'SimulationStudio'). 23 | spec postLoadDoIt: #installPreviewDependencies]; 24 | package: 'TelegramSmalltalkBot-Tests' with: [ 25 | spec requires: #('TelegramSmalltalkBot-Core' 'JSON')]]. 26 | -------------------------------------------------------------------------------- /src/BaselineOfTelegramSmalltalkBot.package/BaselineOfTelegramSmalltalkBot.class/instance/depChangeset..st: -------------------------------------------------------------------------------- 1 | scripts 2 | depChangeset: urlString 3 | 4 | | url response | 5 | url := Url absoluteFromText: urlString. 6 | response := WebClient httpGet: url downloadUrl. 7 | response isSuccess ifFalse: [ 8 | self error: ('Cannot load changeset from {1}: {2}' 9 | format: {urlString. response status})]. 10 | ^ url fileName -> [ 11 | | contents | 12 | contents := response content. 13 | contents readStream fileIn] -------------------------------------------------------------------------------- /src/BaselineOfTelegramSmalltalkBot.package/BaselineOfTelegramSmalltalkBot.class/instance/depMergeVersion..st: -------------------------------------------------------------------------------- 1 | scripts 2 | depMergeVersion: urlString 3 | 4 | | url | 5 | url := Url absoluteFromText: urlString. 6 | ^ url fileName -> [ 7 | | contents version | 8 | contents := url retrieveContents. 9 | version := ((MCVersionReader readerClassForFileNamed: url fileName) 10 | on: contents contentStream) version. 11 | [version merge] 12 | on: MCNoChangesException 13 | do: [:ex | ex resume] 14 | on: MCMergeResolutionRequest 15 | do: [:ex | ex merger conflicts 16 | ifEmpty: [ex resume: true] 17 | ifNotEmpty: [ex pass]]] -------------------------------------------------------------------------------- /src/BaselineOfTelegramSmalltalkBot.package/BaselineOfTelegramSmalltalkBot.class/instance/installPreviewDependencies.st: -------------------------------------------------------------------------------- 1 | scripts 2 | installPreviewDependencies 3 | 4 | | dependencies | 5 | self 6 | flag: #workaround; "As soon as the versions listed here get merged, this should be removed" 7 | flag: #duplication. "See BaselineOfTelegramBot>>#installPreviewDependencies" 8 | 9 | dependencies := { 10 | "Text >> #beAllBold" 11 | self depChangeset: 'http://forum.world.st/attachment/5121467/0/Text-emphasis.1.cs'. 12 | }. 13 | 14 | dependencies 15 | do: [:dep | dep value value] 16 | displayingProgress: [:dep | 'Installing preview dependencies... ({1})' format: {dep key}]. -------------------------------------------------------------------------------- /src/BaselineOfTelegramSmalltalkBot.package/BaselineOfTelegramSmalltalkBot.class/instance/projectClass.st: -------------------------------------------------------------------------------- 1 | accessing 2 | projectClass 3 | 4 | ^ MetacelloCypressBaselineProject -------------------------------------------------------------------------------- /src/BaselineOfTelegramSmalltalkBot.package/BaselineOfTelegramSmalltalkBot.class/methodProperties.json: -------------------------------------------------------------------------------- 1 | { 2 | "class" : { 3 | }, 4 | "instance" : { 5 | "baseline:" : "ct 3/6/2021 03:02", 6 | "depChangeset:" : "ct 3/4/2021 15:20", 7 | "depMergeVersion:" : "ct 11/22/2020 15:57", 8 | "installPreviewDependencies" : "ct 3/4/2021 15:21", 9 | "projectClass" : "ct 11/1/2020 16:46" } } 10 | -------------------------------------------------------------------------------- /src/BaselineOfTelegramSmalltalkBot.package/BaselineOfTelegramSmalltalkBot.class/properties.json: -------------------------------------------------------------------------------- 1 | { 2 | "category" : "BaselineOfTelegramSmalltalkBot", 3 | "classinstvars" : [ 4 | ], 5 | "classvars" : [ 6 | ], 7 | "commentStamp" : "", 8 | "instvars" : [ 9 | ], 10 | "name" : "BaselineOfTelegramSmalltalkBot", 11 | "pools" : [ 12 | ], 13 | "super" : "BaselineOf", 14 | "type" : "normal" } 15 | -------------------------------------------------------------------------------- /src/BaselineOfTelegramSmalltalkBot.package/monticello.meta/categories.st: -------------------------------------------------------------------------------- 1 | SystemOrganization addCategory: #BaselineOfTelegramSmalltalkBot! 2 | -------------------------------------------------------------------------------- /src/BaselineOfTelegramSmalltalkBot.package/monticello.meta/initializers.st: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LinqLover/TelegramSmalltalkBot/9ffd71a4b40aa175aa4e1ae33e42952c84598f9a/src/BaselineOfTelegramSmalltalkBot.package/monticello.meta/initializers.st -------------------------------------------------------------------------------- /src/BaselineOfTelegramSmalltalkBot.package/properties.json: -------------------------------------------------------------------------------- 1 | { 2 | } 3 | -------------------------------------------------------------------------------- /src/TelegramSmalltalkBot-Core.package/.filetree: -------------------------------------------------------------------------------- 1 | { 2 | "noMethodMetaData" : true, 3 | "separateMethodMetaAndSource" : false, 4 | "useCypressPropertiesFile" : true } 5 | -------------------------------------------------------------------------------- /src/TelegramSmalltalkBot-Core.package/.squot-contents: -------------------------------------------------------------------------------- 1 | SquotTrackedObjectMetadata { 2 | #objectClassName : #PackageInfo, 3 | #objectsReplacedByNames : true, 4 | #serializer : #SquotCypressCodeSerializer 5 | } -------------------------------------------------------------------------------- /src/TelegramSmalltalkBot-Core.package/Collection.extension/instance/asTelegramSmalltalkBotMessageFor..st: -------------------------------------------------------------------------------- 1 | *TelegramSmalltalkBot-Core 2 | asTelegramSmalltalkBotMessageFor: aBot 3 | 4 | ^ aBot messageWithCollection: self -------------------------------------------------------------------------------- /src/TelegramSmalltalkBot-Core.package/Collection.extension/methodProperties.json: -------------------------------------------------------------------------------- 1 | { 2 | "class" : { 3 | }, 4 | "instance" : { 5 | "asTelegramSmalltalkBotMessageFor:" : "ct 10/1/2020 14:53" } } 6 | -------------------------------------------------------------------------------- /src/TelegramSmalltalkBot-Core.package/Collection.extension/properties.json: -------------------------------------------------------------------------------- 1 | { 2 | "name" : "Collection" } 3 | -------------------------------------------------------------------------------- /src/TelegramSmalltalkBot-Core.package/CompiledCode.extension/instance/asTelegramSmalltalkBotMessageFor..st: -------------------------------------------------------------------------------- 1 | *TelegramSmalltalkBot-Core 2 | asTelegramSmalltalkBotMessageFor: aBot 3 | 4 | ^ aBot messageWithObject: self -------------------------------------------------------------------------------- /src/TelegramSmalltalkBot-Core.package/CompiledCode.extension/methodProperties.json: -------------------------------------------------------------------------------- 1 | { 2 | "class" : { 3 | }, 4 | "instance" : { 5 | "asTelegramSmalltalkBotMessageFor:" : "ct 10/1/2020 14:39" } } 6 | -------------------------------------------------------------------------------- /src/TelegramSmalltalkBot-Core.package/CompiledCode.extension/properties.json: -------------------------------------------------------------------------------- 1 | { 2 | "name" : "CompiledCode" } 3 | -------------------------------------------------------------------------------- /src/TelegramSmalltalkBot-Core.package/Dictionary.extension/instance/asTelegramSmalltalkBotMessageFor..st: -------------------------------------------------------------------------------- 1 | *TelegramSmalltalkBot-Core 2 | asTelegramSmalltalkBotMessageFor: aBot 3 | 4 | ^ aBot messageWithDictionary: self -------------------------------------------------------------------------------- /src/TelegramSmalltalkBot-Core.package/Dictionary.extension/methodProperties.json: -------------------------------------------------------------------------------- 1 | { 2 | "class" : { 3 | }, 4 | "instance" : { 5 | "asTelegramSmalltalkBotMessageFor:" : "ct 10/1/2020 14:40" } } 6 | -------------------------------------------------------------------------------- /src/TelegramSmalltalkBot-Core.package/Dictionary.extension/properties.json: -------------------------------------------------------------------------------- 1 | { 2 | "name" : "Dictionary" } 3 | -------------------------------------------------------------------------------- /src/TelegramSmalltalkBot-Core.package/Object.extension/instance/asTelegramSmalltalkBotMessageFor..st: -------------------------------------------------------------------------------- 1 | *TelegramSmalltalkBot-Core 2 | asTelegramSmalltalkBotMessageFor: aBot 3 | 4 | (self respondsTo: #asTelegramBotMessageFor:) 5 | ifTrue: [^ self asTelegramBotMessageFor: aBot]. 6 | ^ aBot messageWithObject: self -------------------------------------------------------------------------------- /src/TelegramSmalltalkBot-Core.package/Object.extension/methodProperties.json: -------------------------------------------------------------------------------- 1 | { 2 | "class" : { 3 | }, 4 | "instance" : { 5 | "asTelegramSmalltalkBotMessageFor:" : "ct 10/1/2020 14:39" } } 6 | -------------------------------------------------------------------------------- /src/TelegramSmalltalkBot-Core.package/Object.extension/properties.json: -------------------------------------------------------------------------------- 1 | { 2 | "name" : "Object" } 3 | -------------------------------------------------------------------------------- /src/TelegramSmalltalkBot-Core.package/String.extension/instance/asTelegramSmalltalkBotMessageFor..st: -------------------------------------------------------------------------------- 1 | *TelegramSmalltalkBot-Core 2 | asTelegramSmalltalkBotMessageFor: aBot 3 | 4 | ^ aBot messageWithUserText: self -------------------------------------------------------------------------------- /src/TelegramSmalltalkBot-Core.package/String.extension/instance/tbWithoutLineEndings.st: -------------------------------------------------------------------------------- 1 | *TelegramSmalltalkBot-Core-converting 2 | tbWithoutLineEndings 3 | 4 | ^ self withoutLineEndings -------------------------------------------------------------------------------- /src/TelegramSmalltalkBot-Core.package/String.extension/methodProperties.json: -------------------------------------------------------------------------------- 1 | { 2 | "class" : { 3 | }, 4 | "instance" : { 5 | "asTelegramSmalltalkBotMessageFor:" : "ct 10/2/2020 18:49", 6 | "tbWithoutLineEndings" : "ct 9/9/2020 12:04" } } 7 | -------------------------------------------------------------------------------- /src/TelegramSmalltalkBot-Core.package/String.extension/properties.json: -------------------------------------------------------------------------------- 1 | { 2 | "name" : "String" } 3 | -------------------------------------------------------------------------------- /src/TelegramSmalltalkBot-Core.package/TelegramSmalltalkBot.class/README.md: -------------------------------------------------------------------------------- 1 | I implement the @SqueakSmalltalkBot's logic on Telegram. I am a subclass of TelegramBot from the Telegram Bot framework for Squeak/Smalltalk. My vision is to support passionate Squeakers stay in contact with their image via any platform if they are away from keyboard, simply by sending Smalltalk code to me. My skills include displaying Smalltalk objects via the commands /do, /print, and /inspect, using multimedia representations if appropriate, providing a Workspace-like session environment in which users can store and access variable, and proposing a new kind of scripting workflow which provides a receiver context from the specific message the user is replying to. 2 | 3 | For an exhaustive list of my features, check out the help. 4 | 5 | For debugging purposes, you can set the #isDebugging flag; otherwise, errors occuring while processing a command will be suppressed and sent to the user. -------------------------------------------------------------------------------- /src/TelegramSmalltalkBot-Core.package/TelegramSmalltalkBot.class/class/repositoryStub.st: -------------------------------------------------------------------------------- 1 | repository 2 | repositoryStub 3 | 4 | ^ 'LinqLover/TelegramSmalltalkBot' -------------------------------------------------------------------------------- /src/TelegramSmalltalkBot-Core.package/TelegramSmalltalkBot.class/class/repositoryUrl.st: -------------------------------------------------------------------------------- 1 | repository 2 | repositoryUrl 3 | 4 | ^ 'https://github.com/LinqLover/TelegramSmalltalkBot/' -------------------------------------------------------------------------------- /src/TelegramSmalltalkBot-Core.package/TelegramSmalltalkBot.class/class/repositoryUrlAboutIsolation.st: -------------------------------------------------------------------------------- 1 | repository 2 | repositoryUrlAboutIsolation 3 | 4 | ^ 'https://github.com/LinqLover/TelegramSmalltalkBot/blob/master/src/TelegramSmalltalkBot-Core.package/TelegramSmalltalkSession.class/instance/isolationEnabled.st' -------------------------------------------------------------------------------- /src/TelegramSmalltalkBot-Core.package/TelegramSmalltalkBot.class/class/secrets.st: -------------------------------------------------------------------------------- 1 | accessing 2 | secrets 3 | 4 | ^ self allSubInstances collect: [:bot | 5 | bot instVarNamed: 'token'] -------------------------------------------------------------------------------- /src/TelegramSmalltalkBot-Core.package/TelegramSmalltalkBot.class/instance/answerCommand.message..st: -------------------------------------------------------------------------------- 1 | update handling 2 | answerCommand: aCommand message: aMessage 3 | 4 | ^ aCommand key 5 | caseOf: { 6 | [#do] -> [self answerDo: aMessage]. 7 | [#inspect] -> [self answerInspect: aMessage]. 8 | [#print] -> [self answerPrint: aMessage] } 9 | otherwise: [self messageWithErrorText: 'Command not understood'] -------------------------------------------------------------------------------- /src/TelegramSmalltalkBot-Core.package/TelegramSmalltalkBot.class/instance/answerDo..st: -------------------------------------------------------------------------------- 1 | commands 2 | answerDo: aMessage 3 | "Create a response to the message with a /do command, i.e. evaluate it and answer the #printString of the result." 4 | 5 | ^ self processMessage: aMessage andDo: [:result | 6 | self messageWithUserText: result printString] -------------------------------------------------------------------------------- /src/TelegramSmalltalkBot-Core.package/TelegramSmalltalkBot.class/instance/answerInspect..st: -------------------------------------------------------------------------------- 1 | commands 2 | answerInspect: aMessage 3 | "Respond to the aMessage with an /inspect command, i.e. evaluate it and answer an in-spector-like representation of the result." 4 | 5 | ^ self processMessage: aMessage andDo: [:result | 6 | | fields | 7 | fields := (Inspector inspect: result) fields 8 | collect: [:field | (field name asStringOrText asText removeAttributesThat: [:attrib | 9 | attrib isSupportedByTelegramBot not] 10 | ) -> ([field shouldPrintValueAsIs 11 | ifTrue: [field value asStringOrText] 12 | ifFalse: [field value printString]] 13 | ifError: [self errorText: ''])] 14 | as: OrderedDictionary. 15 | 16 | fields keysAndValuesRemove: [:key :value | 17 | #(self 'all inst vars') includes: key asString]. 18 | (fields associationAt: '...' ifAbsent: [nil]) ifNotNil: [:assoc | 19 | assoc value: (Text 20 | string: (assoc value asString 21 | copyWithRegex: '(?<=Fields named .* not shown.).+(?=>)' 22 | matchesReplacedWith: '') 23 | attributes: {TextEmphasis italic}). 24 | self flag: #wish. "#copyWithRegex:matchesReplacedWith: on Text would be great"]. 25 | 26 | self messageWithUserText: ('{1} {2}\{3}' withCRs asText format: { 27 | result class asString asText beAllBold. 28 | [result printStringLimitedTo: 50] ifError: [ 29 | self errorText: '']. 30 | Text streamContents: [:stream | 31 | fields associations 32 | do: [:assoc | 33 | stream withAttribute: TextEmphasis underlined do: [ 34 | stream nextPutAll: assoc key withBlanksTrimmed]. 35 | stream nextPut: $:; tab. 36 | stream nextPutAll: assoc value withBlanksTrimmed] 37 | separatedBy: [stream cr]]})] -------------------------------------------------------------------------------- /src/TelegramSmalltalkBot-Core.package/TelegramSmalltalkBot.class/instance/answerPrint..st: -------------------------------------------------------------------------------- 1 | commands 2 | answerPrint: aMessage 3 | "Respond to the message with a /print command, i.e. evaluate it and answer an object-specific representation of the result." 4 | 5 | ^ self processMessage: aMessage andDo: [:result | 6 | self messageWith: result] -------------------------------------------------------------------------------- /src/TelegramSmalltalkBot-Core.package/TelegramSmalltalkBot.class/instance/doHelp..st: -------------------------------------------------------------------------------- 1 | commands 2 | doHelp: aMessage 3 | 4 | | helpStrings filteredHelpStrings reply | 5 | helpStrings := self helpStrings. 6 | filteredHelpStrings := {}. 7 | aMessage mainText isEmptyOrNil ifFalse: [ 8 | | commands | 9 | commands := aMessage mainText asString regex: '\b\/?\w+\b' matchesCollect: #yourself. 10 | filteredHelpStrings := Dictionary newFrom: ( 11 | helpStrings associationsSelect: [:assoc | 12 | commands includes: assoc key]). 13 | filteredHelpStrings ifNotEmpty: [ 14 | commands readStream in: [:read | 15 | (read peek = 'help' and: [(read peek: 2) size >= 2]) ifTrue: [ 16 | | writeHelp writeCommand | 17 | writeHelp := WriteStream on: ''. 18 | writeCommand := WriteStream on: ''. 19 | writeHelp nextPutAll: 'Show '; nextPutAll: read peek. 20 | writeCommand nextPutAll: read peek. 21 | [read peek = 'help' and: [(read peek: 2) size >= 2]] whileTrue: [ 22 | writeHelp nextPutAll: ' on '; nextPutAll: read peek. 23 | writeCommand space; nextPutAll: read next]. 24 | writeHelp nextPutAll: ' on '; nextPutAll: read peek. 25 | writeCommand space; nextPutAll: read next. 26 | filteredHelpStrings 27 | removeKey: 'help'; 28 | at: writeCommand contents put: writeHelp contents]. 29 | helpStrings := filteredHelpStrings]]]. 30 | 31 | reply := self replyMessage: aMessage withHtml: (String streamContents: [:stream | 32 | filteredHelpStrings ifEmpty: [ 33 | stream nextPutAll: ('To get started, just send me any valid Smalltalk expression (e. g., {1}). In addition, I understand the following messages:' format: {self generateCodeExample}); cr; cr]. 34 | helpStrings associations 35 | do: [:assoc | stream nextPutAll: ('/{1} - {2}' format: { 36 | assoc key. assoc value})] 37 | separatedBy: [stream cr]. 38 | filteredHelpStrings ifEmpty: [ 39 | stream cr; cr; nextPutAll: 'Furthermore, you can send your messages to any of my previous replies to choose the receiver context accordingly (i. e., to bind self to the object from the reply). Last but not least, if you edit any of your messages, I will update my answers accordingly, so together we can erase every trace of your former slips (who controls the past ...). Have fun!'].]). 40 | 41 | (self sessionFor: aMessage chat) 42 | record: '🥚 Congratulations, you uncovered an easter egg! 🎉' asTextFromHtml "Sticker would be even nicer though" 43 | fromAnswer: reply 44 | bot: self. -------------------------------------------------------------------------------- /src/TelegramSmalltalkBot-Core.package/TelegramSmalltalkBot.class/instance/doReset..st: -------------------------------------------------------------------------------- 1 | commands 2 | doReset: aMessage 3 | 4 | self removeSession: aMessage chat ifAbsent: [^ self]. 5 | 6 | self sendText: 'Session was reset.' toChat: aMessage chat. -------------------------------------------------------------------------------- /src/TelegramSmalltalkBot-Core.package/TelegramSmalltalkBot.class/instance/doStart..st: -------------------------------------------------------------------------------- 1 | commands 2 | doStart: aMessage 3 | 4 | ^ self 5 | replyMessage: aMessage 6 | withHtmls: { 7 | 'Welcome to the Squeak/Smalltalk Bot! 👋 8 | 9 | Just send some random Smalltalk code expressions to me and I will try to evaluate each of them in an up-to-date Squeak image for you – what''s that if not Smalltalk in its loveliest form 😏 10 | 11 | You can also prepend commands such as /do or /print to vary my outputs. For an exhaustive list of all the exciting things we can reach together, send /help.'. 12 | 'This bot is open-source and available on GitHub: 13 | 🐙 {1} 14 | We cordially invite you to visit the repository and to contribute. Your bugs will be fixed and your PRs will be merged!' format: {self class repositoryStub. self class repositoryUrl}. 15 | 'Disclaimer: Since Smalltalk is an open system, all data you share with the bot might be visible to other users. We try to prevent this by providing isolation, but for legal reasons, please consider this bot environment as a social network ...' format: {self class repositoryUrlAboutIsolation}. 16 | 'Carpe Squeak! 🐭' } 17 | beforeSendDo: [:message | 18 | message disableWebPagePreview: true] -------------------------------------------------------------------------------- /src/TelegramSmalltalkBot-Core.package/TelegramSmalltalkBot.class/instance/editMessage.changeTo..st: -------------------------------------------------------------------------------- 1 | message sending 2 | editMessage: oldMessage changeTo: newMessage 3 | "Avoid to add or remove medias to or from the message, which is currently not supported by the API. See comment in superclass." 4 | 5 | (oldMessage isMediaMessage and: [newMessage isMediaMessage not]) ifTrue: [ 6 | newMessage becomeForward: ((newMessage as: TBPhotoMessage) 7 | form: (Form extent: 1 @ 1) "dummy form"; 8 | yourself)]. 9 | (oldMessage isMediaMessage not and: [newMessage isMediaMessage]) ifTrue: [ 10 | newMessage becomeForward: ((newMessage as: TBMessage) 11 | yourself)]. 12 | 13 | ^ super editMessage: oldMessage changeTo: newMessage -------------------------------------------------------------------------------- /src/TelegramSmalltalkBot-Core.package/TelegramSmalltalkBot.class/instance/errorText..st: -------------------------------------------------------------------------------- 1 | private 2 | errorText: aString 3 | 4 | ^ self exceptionText: aString -------------------------------------------------------------------------------- /src/TelegramSmalltalkBot-Core.package/TelegramSmalltalkBot.class/instance/exceptionText..st: -------------------------------------------------------------------------------- 1 | private 2 | exceptionText: aString 3 | 4 | ^ aString asText 5 | beAllItalic; 6 | yourself -------------------------------------------------------------------------------- /src/TelegramSmalltalkBot-Core.package/TelegramSmalltalkBot.class/instance/generateAnswerTo..st: -------------------------------------------------------------------------------- 1 | update handling 2 | generateAnswerTo: aMessage 3 | "Generate an answer message to aMessage without sending it to the API. 4 | This method reimplements command parsing from super's #handleMessage:. The reason is that we want to use the same functionality from #messageEdited: which results in the need of a functional interface." 5 | 6 | | answer | 7 | aMessage text ifNotNil: [:text | 8 | self parseCommandIn: aMessage ifFound: [:command | 9 | answer := self answerCommand: command message: aMessage]]. 10 | 11 | answer ifNil: [answer := self answerPrint: aMessage]. 12 | 13 | ^ answer beReplyTo: aMessage -------------------------------------------------------------------------------- /src/TelegramSmalltalkBot-Core.package/TelegramSmalltalkBot.class/instance/generateCodeExample.st: -------------------------------------------------------------------------------- 1 | private 2 | generateCodeExample 3 | 4 | ^ { 5 | '1 + 2 * 3'. 6 | '2 + 3 * 4'. 7 | '6 * 7'. 8 | 'Float pi i exp stringForReadout'. 9 | '(16 factorial + 1) isPrime'. 10 | '(1 to: 9) join asNumber sqrt truncateTo: 1e-3' 11 | } atRandom -------------------------------------------------------------------------------- /src/TelegramSmalltalkBot-Core.package/TelegramSmalltalkBot.class/instance/handleCommand.message..st: -------------------------------------------------------------------------------- 1 | update handling 2 | handleCommand: aCommand message: aMessage 3 | 4 | ^ aCommand key 5 | caseOf: { 6 | [#start] -> [self doStart: aMessage]. 7 | [#reset] -> [self doReset: aMessage]. 8 | [#help] -> [self doHelp: aMessage]. } 9 | otherwise: [super handleCommand: aCommand message: aMessage] -------------------------------------------------------------------------------- /src/TelegramSmalltalkBot-Core.package/TelegramSmalltalkBot.class/instance/helpStrings.st: -------------------------------------------------------------------------------- 1 | private 2 | helpStrings 3 | 4 | ^ OrderedDictionary new 5 | at: #print put: 'Evaluate the subsequent expression and answer the result'; 6 | at: #do put: 'Evaluate the subsequent expression and answer the result as a printString'; 7 | at: #inspect put: 'Evaluate the subsequent expression and answer an inspector view on the result'; 8 | at: #reset put: 'Delete the entire session and forget that we have ever known each other'; 9 | at: #start put: 'Send the initial greeting message again (just because it is so beautiful)'; 10 | at: #help put: 'Show this help'; 11 | yourself -------------------------------------------------------------------------------- /src/TelegramSmalltalkBot-Core.package/TelegramSmalltalkBot.class/instance/initialize.st: -------------------------------------------------------------------------------- 1 | initialize-release 2 | initialize 3 | 4 | super initialize. 5 | 6 | sessions := Dictionary new. -------------------------------------------------------------------------------- /src/TelegramSmalltalkBot-Core.package/TelegramSmalltalkBot.class/instance/isDebugging..st: -------------------------------------------------------------------------------- 1 | accessing 2 | isDebugging: aBoolean 3 | 4 | isDebugging := aBoolean. -------------------------------------------------------------------------------- /src/TelegramSmalltalkBot-Core.package/TelegramSmalltalkBot.class/instance/isDebugging.st: -------------------------------------------------------------------------------- 1 | accessing 2 | isDebugging 3 | 4 | ^ isDebugging ifNil: [false] -------------------------------------------------------------------------------- /src/TelegramSmalltalkBot-Core.package/TelegramSmalltalkBot.class/instance/logErrorsDuring.replyTo..st: -------------------------------------------------------------------------------- 1 | private 2 | logErrorsDuring: aBlock replyTo: aMessage 3 | 4 | ^ aBlock on: Error, Warning, Halt do: [:error | 5 | self 6 | sendText: (('{1}:\{2}' withCRs asText format: { 7 | 'Sorry, I did something wrong when processing your message' asText beAllBold. 8 | error description }) 9 | addAttribute: TextEmphasis italic; 10 | yourself) 11 | toChat: aMessage chat 12 | replyTo: aMessage. 13 | 14 | self isDebugging ifTrue: [error pass]] -------------------------------------------------------------------------------- /src/TelegramSmalltalkBot-Core.package/TelegramSmalltalkBot.class/instance/messageBlocked.withError..st: -------------------------------------------------------------------------------- 1 | update handling 2 | messageBlocked: aMessage withError: anError 3 | 4 | self removeSession: aMessage chat ifAbsent: []. -------------------------------------------------------------------------------- /src/TelegramSmalltalkBot-Core.package/TelegramSmalltalkBot.class/instance/messageEdited..st: -------------------------------------------------------------------------------- 1 | update handling 2 | messageEdited: aMessage 3 | 4 | | newMessage originalAnswer | 5 | ^ self 6 | logErrorsDuring: [ 7 | originalAnswer := (self sessionFor: aMessage chat) 8 | recordedAnswerTo: aMessage 9 | ifAbsent: [^ self]. 10 | newMessage := self generateAnswerTo: aMessage. 11 | 12 | self editMessage: originalAnswer changeTo: newMessage] 13 | replyTo: aMessage -------------------------------------------------------------------------------- /src/TelegramSmalltalkBot-Core.package/TelegramSmalltalkBot.class/instance/messageReceived..st: -------------------------------------------------------------------------------- 1 | update handling 2 | messageReceived: aMessage 3 | 4 | ^ self 5 | logErrorsDuring: [ 6 | | answer | 7 | answer := self generateAnswerTo: aMessage. 8 | self sendMessage: answer] 9 | replyTo: aMessage -------------------------------------------------------------------------------- /src/TelegramSmalltalkBot-Core.package/TelegramSmalltalkBot.class/instance/messageWith..st: -------------------------------------------------------------------------------- 1 | message creation 2 | messageWith: anObject 3 | 4 | ^ anObject asTelegramSmalltalkBotMessageFor: self -------------------------------------------------------------------------------- /src/TelegramSmalltalkBot-Core.package/TelegramSmalltalkBot.class/instance/messageWithCollection..st: -------------------------------------------------------------------------------- 1 | message creation 2 | messageWithCollection: aCollection 3 | 4 | ^ self 5 | messageWithItems: (aCollection collect: #printString) 6 | caption: ('a {1} with {2} elements:' format: { 7 | aCollection class. 8 | aCollection size }) -------------------------------------------------------------------------------- /src/TelegramSmalltalkBot-Core.package/TelegramSmalltalkBot.class/instance/messageWithDictionary..st: -------------------------------------------------------------------------------- 1 | message creation 2 | messageWithDictionary: aDictionary 3 | 4 | ^ self 5 | messageWithItems: (aDictionary associations collect: #asString) 6 | caption: ('a {1} with {2} elements:' format: { 7 | aDictionary class. 8 | aDictionary size }) -------------------------------------------------------------------------------- /src/TelegramSmalltalkBot-Core.package/TelegramSmalltalkBot.class/instance/messageWithErrorText..st: -------------------------------------------------------------------------------- 1 | private 2 | messageWithErrorText: aString 3 | 4 | ^ self messageWithUserText: (self errorText: aString) -------------------------------------------------------------------------------- /src/TelegramSmalltalkBot-Core.package/TelegramSmalltalkBot.class/instance/messageWithExceptionText..st: -------------------------------------------------------------------------------- 1 | private 2 | messageWithExceptionText: aString 3 | 4 | ^ self messageWithUserText: (self exceptionText: aString) -------------------------------------------------------------------------------- /src/TelegramSmalltalkBot-Core.package/TelegramSmalltalkBot.class/instance/messageWithItems.caption..st: -------------------------------------------------------------------------------- 1 | message creation 2 | messageWithItems: elementStrings caption: aStringOrText 3 | 4 | ^ self messageWithUserText: (Text streamContents: [:stream | 5 | aStringOrText ifNotNil: [stream 6 | nextPutAll: aStringOrText; 7 | cr]. 8 | elementStrings 9 | do: [:each | stream 10 | nextPutAll: '• '; 11 | nextPutAll: each tbWithoutLineEndings] 12 | separatedBy: [stream cr]]) -------------------------------------------------------------------------------- /src/TelegramSmalltalkBot-Core.package/TelegramSmalltalkBot.class/instance/messageWithObject..st: -------------------------------------------------------------------------------- 1 | message creation 2 | messageWithObject: anObject 3 | 4 | ^ self messageWithUserText: anObject asStringOrText -------------------------------------------------------------------------------- /src/TelegramSmalltalkBot-Core.package/TelegramSmalltalkBot.class/instance/messageWithUserText..st: -------------------------------------------------------------------------------- 1 | message creation 2 | messageWithUserText: aStringOrText 3 | 4 | aStringOrText ifEmpty: [ 5 | ^ self messageWithText: ('an empty {1}({2})' format: { 6 | thisContext objectClass: aStringOrText. 7 | thisContext objectIdentityHash: aStringOrText})]. 8 | 9 | ^ self messageWithText: aStringOrText truncated: true -------------------------------------------------------------------------------- /src/TelegramSmalltalkBot-Core.package/TelegramSmalltalkBot.class/instance/processMessage.andDo..st: -------------------------------------------------------------------------------- 1 | command processing 2 | processMessage: aMessage andDo: aBlock 3 | 4 | ^ self processMessage: aMessage andDo: aBlock ifError: [:error | 5 | self messageWithExceptionText: error description asString] -------------------------------------------------------------------------------- /src/TelegramSmalltalkBot-Core.package/TelegramSmalltalkBot.class/instance/processMessage.andDo.ifError..st: -------------------------------------------------------------------------------- 1 | command processing 2 | processMessage: aMessage andDo: resultBlock ifError: errorBlock 3 | 4 | | session result | 5 | session := self sessionFor: aMessage chat. 6 | result := session 7 | processMessage: aMessage 8 | ifError: [:error | ^ session scheduleRecord: error fromAnswer: [errorBlock cull: error]]. 9 | ^ session scheduleRecord: result fromAnswer: [resultBlock value: result] -------------------------------------------------------------------------------- /src/TelegramSmalltalkBot-Core.package/TelegramSmalltalkBot.class/instance/removeSession.ifAbsent..st: -------------------------------------------------------------------------------- 1 | accessing - sessions 2 | removeSession: aChat ifAbsent: aBlock 3 | 4 | | session | 5 | session := sessions 6 | removeKey: aChat id 7 | ifAbsent: [^ aBlock value]. 8 | session reset. "This would be redundant but helps us fulfill possible duties of deletion before GC rules." -------------------------------------------------------------------------------- /src/TelegramSmalltalkBot-Core.package/TelegramSmalltalkBot.class/instance/replyMessage.withHtml..st: -------------------------------------------------------------------------------- 1 | message sending 2 | replyMessage: aMessage withHtml: htmlString 3 | 4 | ^ (self 5 | replyMessage: aMessage 6 | withHtmls: {htmlString} 7 | beforeSendDo: [:message |]) anyOne -------------------------------------------------------------------------------- /src/TelegramSmalltalkBot-Core.package/TelegramSmalltalkBot.class/instance/replyMessage.withHtmls.beforeSendDo..st: -------------------------------------------------------------------------------- 1 | message sending 2 | replyMessage: aMessage withHtmls: htmlStrings beforeSendDo: messageBlock 3 | 4 | ^ htmlStrings collect: [:htmlString | 5 | | text message | 6 | text := (HtmlReadWriter on: htmlString readStream) 7 | breakLines: false; 8 | nextText. 9 | message := self messageWithText: text. 10 | messageBlock value: message. 11 | self 12 | sendMessage: message 13 | toChat: aMessage chat] -------------------------------------------------------------------------------- /src/TelegramSmalltalkBot-Core.package/TelegramSmalltalkBot.class/instance/sessionFor..st: -------------------------------------------------------------------------------- 1 | accessing - sessions 2 | sessionFor: aChat 3 | 4 | ^ sessions 5 | at: aChat id 6 | ifAbsentPut: [TelegramSmalltalkSession new] -------------------------------------------------------------------------------- /src/TelegramSmalltalkBot-Core.package/TelegramSmalltalkBot.class/methodProperties.json: -------------------------------------------------------------------------------- 1 | { 2 | "class" : { 3 | "repositoryStub" : "ct 3/6/2021 04:12", 4 | "repositoryUrl" : "ct 3/6/2021 04:12", 5 | "repositoryUrlAboutIsolation" : "ct 3/7/2021 17:31", 6 | "secrets" : "ct 3/6/2021 13:17" }, 7 | "instance" : { 8 | "answerCommand:message:" : "ct 10/3/2020 14:47", 9 | "answerDo:" : "ct 10/3/2020 14:57", 10 | "answerInspect:" : "ct 3/5/2021 14:45", 11 | "answerPrint:" : "ct 10/3/2020 14:57", 12 | "doHelp:" : "ct 3/7/2021 23:55", 13 | "doReset:" : "ct 10/3/2020 18:39", 14 | "doStart:" : "ct 3/7/2021 20:25", 15 | "editMessage:changeTo:" : "ct 10/3/2020 18:48", 16 | "errorText:" : "ct 10/3/2020 14:48", 17 | "exceptionText:" : "ct 10/3/2020 14:48", 18 | "generateAnswerTo:" : "ct 10/3/2020 15:06", 19 | "generateCodeExample" : "ct 3/7/2021 23:38", 20 | "handleCommand:message:" : "ct 3/6/2021 04:05", 21 | "helpStrings" : "ct 3/7/2021 23:53", 22 | "initialize" : "ct 9/9/2020 13:16", 23 | "isDebugging" : "ct 9/22/2020 01:17", 24 | "isDebugging:" : "ct 9/22/2020 01:17", 25 | "logErrorsDuring:replyTo:" : "ct 10/3/2020 18:34", 26 | "messageBlocked:withError:" : "ct 3/22/2021 14:22", 27 | "messageEdited:" : "ct 10/3/2020 13:21", 28 | "messageReceived:" : "ct 10/3/2020 14:58", 29 | "messageWith:" : "ct 10/2/2020 18:47", 30 | "messageWithCollection:" : "ct 9/22/2020 01:53", 31 | "messageWithDictionary:" : "ct 9/22/2020 02:22", 32 | "messageWithErrorText:" : "ct 10/3/2020 17:46", 33 | "messageWithExceptionText:" : "ct 10/3/2020 17:46", 34 | "messageWithItems:caption:" : "ct 1/24/2021 21:31", 35 | "messageWithObject:" : "ct 10/2/2020 18:49", 36 | "messageWithUserText:" : "ct 10/2/2020 18:52", 37 | "processMessage:andDo:" : "ct 10/3/2020 14:58", 38 | "processMessage:andDo:ifError:" : "ct 10/3/2020 14:59", 39 | "removeSession:ifAbsent:" : "ct 10/3/2020 16:08", 40 | "replyMessage:withHtml:" : "ct 3/7/2021 23:39", 41 | "replyMessage:withHtmls:beforeSendDo:" : "ct 3/7/2021 23:39", 42 | "sessionFor:" : "ct 10/3/2020 16:13" } } 43 | -------------------------------------------------------------------------------- /src/TelegramSmalltalkBot-Core.package/TelegramSmalltalkBot.class/properties.json: -------------------------------------------------------------------------------- 1 | { 2 | "category" : "TelegramSmalltalkBot-Core", 3 | "classinstvars" : [ 4 | ], 5 | "classvars" : [ 6 | ], 7 | "commentStamp" : "ct 10/3/2020 21:28", 8 | "instvars" : [ 9 | "sessions", 10 | "isDebugging" ], 11 | "name" : "TelegramSmalltalkBot", 12 | "pools" : [ 13 | ], 14 | "super" : "TelegramBot", 15 | "type" : "normal" } 16 | -------------------------------------------------------------------------------- /src/TelegramSmalltalkBot-Core.package/TelegramSmalltalkSession.class/README.md: -------------------------------------------------------------------------------- 1 | I represent the session environment of a TelegramSmalltalkBot for a particular user. I am capable of holding variable bindings, remembering message references and outputs, and evaluating user code against the session context. 2 | 3 | Instance Variables 4 | bindings: Dictionary that maps strings to user objects. 5 | answers: WeakValueDictionary that stores message sent by the bot associated with their IDs. Used to edit these messages if the referenced message has been edited. 6 | pinnedAnswers: Collection that holds strong references to the answers. See explanation of pinning below. 7 | results: WeakValueDictionary that stores output objects of messages sent by the bot, associated with the messages' IDs. Used to provide the receiver context for a user message referencing to an earlier bot message. 8 | pinnedResults: Collection that holds strong references to the results. See explanation of pinning below. 9 | pinnedClosures: WeakKeyDictionary that holds references to BlockClosures that are registered in the weak-referencing EventManager database. 10 | 11 | # Pinning 12 | To serve scalability when running a bot with many frequent users, I support automatic recycling of older session contents ("records") by making use of the GC. To implement this, the relevant records theirselves (answers and results) are hold using weak references only, and a limittable list of the most recent records is kept in memory using the pinned collections. See #tidyUpRecords: for releasing older records. -------------------------------------------------------------------------------- /src/TelegramSmalltalkBot-Core.package/TelegramSmalltalkSession.class/instance/basicRecordAnswer..st: -------------------------------------------------------------------------------- 1 | records 2 | basicRecordAnswer: aMessage 3 | 4 | answers 5 | at: aMessage referenceMessageId 6 | put: aMessage. 7 | self pinRecord: aMessage to: pinnedAnswers. -------------------------------------------------------------------------------- /src/TelegramSmalltalkBot-Core.package/TelegramSmalltalkSession.class/instance/basicRecordResult.forMessage..st: -------------------------------------------------------------------------------- 1 | records 2 | basicRecordResult: anObject forMessage: aMessage 3 | 4 | results 5 | at: aMessage messageId 6 | put: anObject. 7 | self pinRecord: anObject to: pinnedResults. -------------------------------------------------------------------------------- /src/TelegramSmalltalkBot-Core.package/TelegramSmalltalkSession.class/instance/bindingOf..st: -------------------------------------------------------------------------------- 1 | binding 2 | bindingOf: aString 3 | 4 | self mustDeclareVariables ifTrue: [^ super bindingOf: aString]. 5 | 6 | (bindings includesKey: aString) ifFalse: [ 7 | bindings at: aString put: nil]. 8 | ^ bindings associationAt: aString -------------------------------------------------------------------------------- /src/TelegramSmalltalkBot-Core.package/TelegramSmalltalkSession.class/instance/doSafely.ifError..st: -------------------------------------------------------------------------------- 1 | evaluation 2 | doSafely: aBlock ifError: errorBlock 3 | 4 | self flag: #extend. "Here is much more potential for isolation. Transcript forwarding, ToolSet installation, timeouts ..." 5 | 6 | thisContext wrap: [:wrapped | wrapped 7 | valueWithin: 60 seconds 8 | onTimeout: [errorBlock value: 'Expression timed out']]. 9 | 10 | ^ self 11 | doSafely:[ 12 | thisContext wrap: [:wrapped | SystemChangeNotifier uniqueInstance doSilently: wrapped]. 13 | aBlock value] 14 | on: ProvideAnswerNotification, (Error, Warning, Halt), UnhandledError 15 | do: [:error | errorBlock cull: error] 16 | useSandbox: self isolationEnabled -------------------------------------------------------------------------------- /src/TelegramSmalltalkBot-Core.package/TelegramSmalltalkSession.class/instance/doSafely.on.do.useSandbox..st: -------------------------------------------------------------------------------- 1 | evaluation 2 | doSafely: aBlock on: exceptionHandler do: exceptionBlock useSandbox: shouldUseSandbox 3 | 4 | | sandbox result | 5 | shouldUseSandbox ifFalse: [ 6 | ^ aBlock on: exceptionHandler do: exceptionBlock]. 7 | 8 | thisContext insertSender: (Context contextOn: SandboxError do: exceptionBlock). 9 | sandbox := (sandboxMemory ifNil: [Sandbox new] ifNotNil: [Sandbox fromMemory: sandboxMemory]) 10 | stepLimit: 10000000; 11 | flag: #todo; "garbage-collect side effects that are not related to bindings" 12 | yourself. 13 | {bindings. bindings array} , bindings array , bindings values do: [:ea | 14 | sandbox addObject: ea]. 15 | self secrets do: [:secret | 16 | sandbox patchObject: secret with: ( 17 | self obfuscateSecret: secret)]. 18 | 19 | result := sandbox 20 | evaluate: aBlock 21 | on: exceptionHandler 22 | do: exceptionBlock. 23 | sandboxMemory := sandbox exportMemory. 24 | self maximumMemorySize ifNotNil: [:maxSize | 25 | | memSize | 26 | memSize := sandboxMemory memorySize. 27 | memSize > maxSize ifTrue: [ 28 | [self notify: 'I''m sorry, but you have exceeded your memory limit. Everything will be wiped now'] 29 | ensure: [sandboxMemory := nil]]. 30 | memSize > (maxSize // 2) ifTrue: [ 31 | "self notify: 'You have reached {1}% of your memory limit now. Maybe think about an upgrade or back up your data?'." 32 | self flag: #todo. "A mechanism for warning the user without aborting execution - maybe resume after Warnings by default? But would break threading structure. Or write all warnings into single message?"]]. 33 | 34 | self flag: #hack. "Problem: Secret could be anywhere deeply nested in a real object" 35 | (self secrets anySatisfy: [:secret | (result longPrintString ifNil: ['']) includesSubstring: (secret ifNil: [''])]) 36 | ifTrue: [^ nil]. 37 | 38 | ^ result -------------------------------------------------------------------------------- /src/TelegramSmalltalkBot-Core.package/TelegramSmalltalkSession.class/instance/evaluate.for.ifError..st: -------------------------------------------------------------------------------- 1 | evaluation 2 | evaluate: aString for: receiver ifError: aBlock 3 | 4 | ^ self 5 | doSafely: [Compiler new 6 | evaluate: aString 7 | in: nil 8 | to: receiver 9 | environment: Smalltalk globals 10 | notifying: self 11 | ifFail: [aBlock value] 12 | logged: false] 13 | ifError: aBlock -------------------------------------------------------------------------------- /src/TelegramSmalltalkBot-Core.package/TelegramSmalltalkSession.class/instance/initialize.st: -------------------------------------------------------------------------------- 1 | initialize-release 2 | initialize 3 | 4 | super initialize. 5 | 6 | bindings := Dictionary new. 7 | answers := WeakValueDictionary new. 8 | results := WeakValueDictionary new. 9 | pinnedAnswers := OrderedCollection new. 10 | pinnedResults := OrderedCollection new. 11 | pinnedClosures := WeakKeyDictionary new. -------------------------------------------------------------------------------- /src/TelegramSmalltalkBot-Core.package/TelegramSmalltalkSession.class/instance/isolationEnabled..st: -------------------------------------------------------------------------------- 1 | accessing 2 | isolationEnabled: aBoolean 3 | 4 | isolationEnabled := aBoolean. -------------------------------------------------------------------------------- /src/TelegramSmalltalkBot-Core.package/TelegramSmalltalkSession.class/instance/isolationEnabled.st: -------------------------------------------------------------------------------- 1 | accessing 2 | isolationEnabled 3 | 4 | ^ isolationEnabled ifNil: [true] -------------------------------------------------------------------------------- /src/TelegramSmalltalkBot-Core.package/TelegramSmalltalkSession.class/instance/maximumMemorySize.st: -------------------------------------------------------------------------------- 1 | accessing 2 | maximumMemorySize 3 | "nil means the GC is disabled" 4 | 5 | ^ 1000000 -------------------------------------------------------------------------------- /src/TelegramSmalltalkBot-Core.package/TelegramSmalltalkSession.class/instance/maximumRecordSize.st: -------------------------------------------------------------------------------- 1 | accessing 2 | maximumRecordSize 3 | "nil means the GC is disabled" 4 | 5 | ^ nil -------------------------------------------------------------------------------- /src/TelegramSmalltalkBot-Core.package/TelegramSmalltalkSession.class/instance/mustDeclareVariables.st: -------------------------------------------------------------------------------- 1 | accessing 2 | mustDeclareVariables 3 | 4 | ^ false -------------------------------------------------------------------------------- /src/TelegramSmalltalkBot-Core.package/TelegramSmalltalkSession.class/instance/notify.at.in..st: -------------------------------------------------------------------------------- 1 | evaluation 2 | notify: aString at: location in: source 3 | 4 | | error | 5 | error := (SyntaxErrorNotification 6 | cue: (CompilationCue source: source contents) 7 | doitFlag: true 8 | errorMessage: aString 9 | location: location) signal. 10 | error tryNewSourceIfAvailable. -------------------------------------------------------------------------------- /src/TelegramSmalltalkBot-Core.package/TelegramSmalltalkSession.class/instance/obfuscateSecret..st: -------------------------------------------------------------------------------- 1 | private 2 | obfuscateSecret: secret 3 | "Don't let the user be aware of that they were dealing with a secret, just obfuscate it" 4 | 5 | | characters | 6 | secret isText ifTrue: [ 7 | ^ Text string: (self obfuscateSecret: secret string) runs: secret runs]. 8 | secret isString ifFalse: [^ nil]. 9 | 10 | characters := ($a to: $z) , ($A to: $Z) , ($0 to: $9). 11 | ^ (1 to: secret size) 12 | collect: [:i | characters atRandom] 13 | as: String -------------------------------------------------------------------------------- /src/TelegramSmalltalkBot-Core.package/TelegramSmalltalkSession.class/instance/pinRecord.to..st: -------------------------------------------------------------------------------- 1 | records 2 | pinRecord: anObject to: pinnedRecords 3 | 4 | pinnedRecords addLast: anObject. 5 | 6 | "Could be theoretically deferred" 7 | self tidyUpRecords: pinnedRecords. -------------------------------------------------------------------------------- /src/TelegramSmalltalkBot-Core.package/TelegramSmalltalkSession.class/instance/processMessage.ifError..st: -------------------------------------------------------------------------------- 1 | message processing 2 | processMessage: aMessage ifError: aBlock 3 | 4 | ^ self 5 | evaluate: aMessage mainText 6 | for: (self receiverFor: aMessage replyToMessage) 7 | ifError: aBlock -------------------------------------------------------------------------------- /src/TelegramSmalltalkBot-Core.package/TelegramSmalltalkSession.class/instance/receiverFor..st: -------------------------------------------------------------------------------- 1 | accessing 2 | receiverFor: aMessage 3 | 4 | aMessage ifNil: [^ nil]. 5 | ^ results 6 | at: aMessage messageId 7 | ifAbsent: [nil] -------------------------------------------------------------------------------- /src/TelegramSmalltalkBot-Core.package/TelegramSmalltalkSession.class/instance/record.fromAnswer.bot..st: -------------------------------------------------------------------------------- 1 | records 2 | record: anObject fromAnswer: aMessage bot: aBot 3 | 4 | self basicRecordAnswer: aMessage. 5 | self basicRecordResult: anObject forMessage: aMessage. 6 | 7 | answers 8 | select: [:answer | (answer referenceMessage ifNotNil: #replyToMessage) 9 | ifNil: [false] 10 | ifNotNil: [:previousAnswer | previousAnswer messageId = aMessage messageId]] 11 | thenDo: [:answer | aBot handleEditedMessage: answer referenceMessage]. -------------------------------------------------------------------------------- /src/TelegramSmalltalkBot-Core.package/TelegramSmalltalkSession.class/instance/recordedAnswerTo.ifAbsent..st: -------------------------------------------------------------------------------- 1 | records 2 | recordedAnswerTo: aMessage ifAbsent: aBlock 3 | 4 | ^ answers 5 | at: aMessage messageId 6 | ifAbsent: aBlock -------------------------------------------------------------------------------- /src/TelegramSmalltalkBot-Core.package/TelegramSmalltalkSession.class/instance/reset.st: -------------------------------------------------------------------------------- 1 | initialize-release 2 | reset 3 | 4 | bindings removeAll. 5 | answers removeAll. 6 | results removeAll. 7 | pinnedAnswers removeAll. 8 | pinnedResults removeAll. 9 | pinnedClosures removeAll. -------------------------------------------------------------------------------- /src/TelegramSmalltalkBot-Core.package/TelegramSmalltalkSession.class/instance/scheduleRecord.fromAnswer..st: -------------------------------------------------------------------------------- 1 | records 2 | scheduleRecord: anObject fromAnswer: aBlock 3 | 4 | | answer scheduledBlock | 5 | answer := aBlock value. 6 | answer ifNil: [^ answer]. 7 | 8 | scheduledBlock := [:bot | self record: anObject fromAnswer: answer bot: bot]. 9 | answer 10 | when: #sent 11 | send: #value: 12 | to: scheduledBlock. 13 | pinnedClosures at: answer put: scheduledBlock. 14 | 15 | ^ answer -------------------------------------------------------------------------------- /src/TelegramSmalltalkBot-Core.package/TelegramSmalltalkSession.class/instance/secrets.st: -------------------------------------------------------------------------------- 1 | private 2 | secrets 3 | 4 | ^ TelegramSmalltalkBot secrets -------------------------------------------------------------------------------- /src/TelegramSmalltalkBot-Core.package/TelegramSmalltalkSession.class/instance/tidyUpRecords..st: -------------------------------------------------------------------------------- 1 | records 2 | tidyUpRecords: pinnedRecords 3 | 4 | | overrun | 5 | overrun := pinnedRecords size - (self maximumRecordSize ifNil: [^ self]). 6 | overrun <= 0 ifTrue: [^ self]. 7 | 8 | pinnedRecords removeFirst: overrun. -------------------------------------------------------------------------------- /src/TelegramSmalltalkBot-Core.package/TelegramSmalltalkSession.class/instance/wantsInteractiveErrorCorrection.st: -------------------------------------------------------------------------------- 1 | evaluation 2 | wantsInteractiveErrorCorrection 3 | 4 | ^ false -------------------------------------------------------------------------------- /src/TelegramSmalltalkBot-Core.package/TelegramSmalltalkSession.class/methodProperties.json: -------------------------------------------------------------------------------- 1 | { 2 | "class" : { 3 | }, 4 | "instance" : { 5 | "basicRecordAnswer:" : "ct 9/29/2020 14:23", 6 | "basicRecordResult:forMessage:" : "ct 9/29/2020 14:23", 7 | "bindingOf:" : "ct 9/9/2020 13:59", 8 | "doSafely:ifError:" : "ct 3/6/2021 02:10", 9 | "doSafely:on:do:useSandbox:" : "ct 3/6/2021 14:34", 10 | "evaluate:for:ifError:" : "ct 10/3/2020 18:46", 11 | "initialize" : "ct 10/2/2020 15:51", 12 | "isolationEnabled" : "ct 3/6/2021 02:10", 13 | "isolationEnabled:" : "ct 3/6/2021 02:10", 14 | "maximumMemorySize" : "ct 3/6/2021 02:37", 15 | "maximumRecordSize" : "ct 10/3/2020 21:55", 16 | "mustDeclareVariables" : "ct 9/9/2020 13:52", 17 | "notify:at:in:" : "ct 3/6/2021 14:22", 18 | "obfuscateSecret:" : "ct 3/6/2021 13:25", 19 | "pinRecord:to:" : "ct 9/29/2020 14:23", 20 | "processMessage:ifError:" : "ct 10/3/2020 14:34", 21 | "receiverFor:" : "ct 10/3/2020 16:05", 22 | "record:fromAnswer:bot:" : "ct 3/7/2021 23:45", 23 | "recordedAnswerTo:ifAbsent:" : "ct 9/29/2020 14:24", 24 | "reset" : "ct 10/2/2020 16:01", 25 | "scheduleRecord:fromAnswer:" : "ct 10/2/2020 15:52", 26 | "secrets" : "ct 3/6/2021 13:26", 27 | "tidyUpRecords:" : "ct 9/29/2020 14:19", 28 | "wantsInteractiveErrorCorrection" : "ct 9/9/2020 13:47" } } 29 | -------------------------------------------------------------------------------- /src/TelegramSmalltalkBot-Core.package/TelegramSmalltalkSession.class/properties.json: -------------------------------------------------------------------------------- 1 | { 2 | "category" : "TelegramSmalltalkBot-Core", 3 | "classinstvars" : [ 4 | ], 5 | "classvars" : [ 6 | ], 7 | "commentStamp" : "ct 3/6/2021 02:15", 8 | "instvars" : [ 9 | "bindings", 10 | "answers", 11 | "pinnedAnswers", 12 | "results", 13 | "pinnedResults", 14 | "pinnedClosures", 15 | "isolationEnabled", 16 | "sandboxMemory" ], 17 | "name" : "TelegramSmalltalkSession", 18 | "pools" : [ 19 | ], 20 | "super" : "Object", 21 | "type" : "normal" } 22 | -------------------------------------------------------------------------------- /src/TelegramSmalltalkBot-Core.package/Text.extension/instance/asTelegramSmalltalkBotMessageFor..st: -------------------------------------------------------------------------------- 1 | *TelegramSmalltalkBot-Core 2 | asTelegramSmalltalkBotMessageFor: aBot 3 | 4 | ^ aBot messageWithUserText: self -------------------------------------------------------------------------------- /src/TelegramSmalltalkBot-Core.package/Text.extension/methodProperties.json: -------------------------------------------------------------------------------- 1 | { 2 | "class" : { 3 | }, 4 | "instance" : { 5 | "asTelegramSmalltalkBotMessageFor:" : "ct 10/2/2020 18:49" } } 6 | -------------------------------------------------------------------------------- /src/TelegramSmalltalkBot-Core.package/Text.extension/properties.json: -------------------------------------------------------------------------------- 1 | { 2 | "name" : "Text" } 3 | -------------------------------------------------------------------------------- /src/TelegramSmalltalkBot-Core.package/monticello.meta/categories.st: -------------------------------------------------------------------------------- 1 | SystemOrganization addCategory: #'TelegramSmalltalkBot-Core'! 2 | -------------------------------------------------------------------------------- /src/TelegramSmalltalkBot-Core.package/monticello.meta/initializers.st: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LinqLover/TelegramSmalltalkBot/9ffd71a4b40aa175aa4e1ae33e42952c84598f9a/src/TelegramSmalltalkBot-Core.package/monticello.meta/initializers.st -------------------------------------------------------------------------------- /src/TelegramSmalltalkBot-Core.package/properties.json: -------------------------------------------------------------------------------- 1 | { 2 | } 3 | -------------------------------------------------------------------------------- /src/TelegramSmalltalkBot-Tests.package/.filetree: -------------------------------------------------------------------------------- 1 | { 2 | "noMethodMetaData" : true, 3 | "separateMethodMetaAndSource" : false, 4 | "useCypressPropertiesFile" : true } 5 | -------------------------------------------------------------------------------- /src/TelegramSmalltalkBot-Tests.package/.squot-contents: -------------------------------------------------------------------------------- 1 | SquotTrackedObjectMetadata { 2 | #objectClassName : #PackageInfo, 3 | #objectsReplacedByNames : true, 4 | #serializer : #SquotCypressCodeSerializer 5 | } -------------------------------------------------------------------------------- /src/TelegramSmalltalkBot-Tests.package/TelegramSmalltalkBotTest.class/README.md: -------------------------------------------------------------------------------- 1 | I provide acceptance tests for the TelegramSmalltalkBot. An ugly kind of mocking is used for isolating the bot class from the API, which should probably be replaced by composition. See #setUp and note in the class comment of TelegramBot. -------------------------------------------------------------------------------- /src/TelegramSmalltalkBot-Tests.package/TelegramSmalltalkBotTest.class/instance/askBot..st: -------------------------------------------------------------------------------- 1 | support 2 | askBot: aMessage 3 | 4 | (aMessage respondsTo: #messageId) ifFalse: [ 5 | ^ self askBot: (self makeMessageFrom: aMessage)]. 6 | 7 | ^ self receiveBotMessagesDuring: [ 8 | bot handleMessage: aMessage] -------------------------------------------------------------------------------- /src/TelegramSmalltalkBot-Tests.package/TelegramSmalltalkBotTest.class/instance/botSession.st: -------------------------------------------------------------------------------- 1 | support 2 | botSession 3 | 4 | ^ bot sessionFor: self makeChat -------------------------------------------------------------------------------- /src/TelegramSmalltalkBot-Tests.package/TelegramSmalltalkBotTest.class/instance/clientChatId.st: -------------------------------------------------------------------------------- 1 | accessing 2 | clientChatId 3 | 4 | ^ 42 -------------------------------------------------------------------------------- /src/TelegramSmalltalkBot-Tests.package/TelegramSmalltalkBotTest.class/instance/editMessage.text..st: -------------------------------------------------------------------------------- 1 | watcher 2 | editMessage: aMessage text: aStringOrText 3 | 4 | editedMessages at: aMessage messageId put: aStringOrText. 5 | 6 | aMessage text: aStringOrText. 7 | ^ aMessage -------------------------------------------------------------------------------- /src/TelegramSmalltalkBot-Tests.package/TelegramSmalltalkBotTest.class/instance/makeChat.st: -------------------------------------------------------------------------------- 1 | support 2 | makeChat 3 | 4 | ^ JsonObject new 5 | at: #id put: self clientChatId; 6 | yourself -------------------------------------------------------------------------------- /src/TelegramSmalltalkBot-Tests.package/TelegramSmalltalkBotTest.class/instance/makeMessageFrom..st: -------------------------------------------------------------------------------- 1 | support 2 | makeMessageFrom: anObject 3 | 4 | | message | 5 | (anObject isString or: [anObject isText]) ifFalse: [ 6 | self fail: 'Message type not yet suppported!']. 7 | 8 | message := JsonObject new 9 | at: #text put: anObject; 10 | at: #messageId put: self nextMessageId; 11 | at: #from put: self makeChat; 12 | at: #chat put: (JsonObject new 13 | at: #id put: self clientChatId; 14 | at: #type put: #private; 15 | yourself); 16 | yourself. 17 | 18 | "Add missing TBTextCommand attributes" 19 | message text ifNotNil: [:text | | commandRanges newText | 20 | newText := text asText copy. 21 | commandRanges := newText string allRangesOfRegexMatches: '(?Squeak'' asTextFromHtml' 6 | answerSatisfy: [:answer | 7 | self 8 | assert: 'Squeak' 9 | equals: answer text printHtmlString]. -------------------------------------------------------------------------------- /src/TelegramSmalltalkBot-Tests.package/TelegramSmalltalkBotTest.class/instance/testVariables.st: -------------------------------------------------------------------------------- 1 | tests 2 | testVariables 3 | 4 | self askBot: '/reset'. 5 | 6 | self 7 | shouldBotAsked: 'x := 1. y := x + 1' 8 | answer: '2'. 9 | self 10 | shouldBotAsked: 'y + 1' 11 | answer: '3'. 12 | 13 | self 14 | shouldBotAsked: '/reset' 15 | answerSatisfy: [:answer | 16 | answer text asString asLowercase includesSubstring: 'session']. 17 | self 18 | shouldBotAsked: 'y + 1' 19 | answerSatisfy: [:answer | 20 | answer text asString includesSubstring: 'MessageNotUnderstood: UndefinedObject'] -------------------------------------------------------------------------------- /src/TelegramSmalltalkBot-Tests.package/TelegramSmalltalkBotTest.class/methodProperties.json: -------------------------------------------------------------------------------- 1 | { 2 | "class" : { 3 | }, 4 | "instance" : { 5 | "askBot:" : "ct 10/3/2020 14:36", 6 | "botSession" : "ct 3/6/2021 02:14", 7 | "clientChatId" : "ct 10/2/2020 16:07", 8 | "editMessage:text:" : "ct 10/2/2020 16:03", 9 | "makeChat" : "ct 3/6/2021 02:14", 10 | "makeMessageFrom:" : "ct 3/6/2021 02:13", 11 | "nextMessageId" : "ct 9/22/2020 00:03", 12 | "receiveBotMessagesDuring:" : "ct 10/2/2020 14:30", 13 | "receiveEditedBotMessagesDuring:" : "ct 10/2/2020 16:04", 14 | "sendMessage:" : "ct 10/2/2020 16:05", 15 | "setUp" : "ct 11/1/2020 18:02", 16 | "shouldBotAsked:answer:" : "ct 10/2/2020 14:27", 17 | "shouldBotAsked:answerSatisfy:" : "ct 10/2/2020 16:14", 18 | "shouldBotAsked:answersSatisfy:" : "ct 3/7/2021 17:16", 19 | "someNumber" : "ct 9/21/2020 19:50", 20 | "someString" : "ct 9/21/2020 19:12", 21 | "tearDown" : "ct 9/22/2020 00:59", 22 | "testAnimation" : "ct 10/3/2020 18:50", 23 | "testDialog" : "ct 10/2/2020 14:51", 24 | "testDo" : "ct 9/21/2020 19:52", 25 | "testEditMessage" : "ct 10/2/2020 16:16", 26 | "testForm" : "ct 9/21/2020 21:45", 27 | "testHelp" : "ct 3/7/2021 17:20", 28 | "testInspect" : "ct 9/21/2020 20:09", 29 | "testInternalError" : "ct 3/6/2021 02:13", 30 | "testPrint" : "ct 9/21/2020 21:45", 31 | "testRuntimeError" : "ct 9/21/2020 22:48", 32 | "testSimple" : "ct 9/21/2020 19:49", 33 | "testSound" : "ct 9/21/2020 21:45", 34 | "testStart" : "ct 3/7/2021 17:18", 35 | "testSyntaxError" : "ct 9/21/2020 22:23", 36 | "testText" : "ct 9/21/2020 22:21", 37 | "testVariables" : "ct 10/2/2020 14:28" } } 38 | -------------------------------------------------------------------------------- /src/TelegramSmalltalkBot-Tests.package/TelegramSmalltalkBotTest.class/properties.json: -------------------------------------------------------------------------------- 1 | { 2 | "category" : "TelegramSmalltalkBot-Tests", 3 | "classinstvars" : [ 4 | ], 5 | "classvars" : [ 6 | ], 7 | "commentStamp" : "ct 10/3/2020 21:57", 8 | "instvars" : [ 9 | "bot", 10 | "lastMessageId", 11 | "receivedMessages", 12 | "editedMessages" ], 13 | "name" : "TelegramSmalltalkBotTest", 14 | "pools" : [ 15 | ], 16 | "super" : "TestCase", 17 | "type" : "normal" } 18 | -------------------------------------------------------------------------------- /src/TelegramSmalltalkBot-Tests.package/monticello.meta/categories.st: -------------------------------------------------------------------------------- 1 | SystemOrganization addCategory: #'TelegramSmalltalkBot-Tests'! 2 | -------------------------------------------------------------------------------- /src/TelegramSmalltalkBot-Tests.package/monticello.meta/initializers.st: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LinqLover/TelegramSmalltalkBot/9ffd71a4b40aa175aa4e1ae33e42952c84598f9a/src/TelegramSmalltalkBot-Tests.package/monticello.meta/initializers.st -------------------------------------------------------------------------------- /src/TelegramSmalltalkBot-Tests.package/properties.json: -------------------------------------------------------------------------------- 1 | { 2 | } 3 | --------------------------------------------------------------------------------