|
4 years ago | |
---|---|---|
config | 4 years ago | |
lib | 4 years ago | |
src | 4 years ago | |
.dockerignore | 5 years ago | |
.drone.yml | 4 years ago | |
.gitignore | 5 years ago | |
Dockerfile | 4 years ago | |
LICENSE | 6 years ago | |
README.md | 4 years ago | |
TODO_commands | 6 years ago | |
mkplugin.sh | 5 years ago | |
requirements.txt | 4 years ago | |
rollbot-docker.sh | 5 years ago | |
rollbot-local.sh | 5 years ago |
Running Rollbot requires either Docker or Python 3.7 to be installed on your machine. Additionally, there is some one-time set up, detailed here
Open GroupMe through your preferred application, and create a new chat containing just yourself. This will be your testing chat, where your local copy of rollbot will post messages. Future plans for the project include a simpler local testing environment, but integrating with GroupMe is an important testing step regardless, and so it is reasonable to do it now anyway.
Next, create a config/secrets.toml
file. Do NOT commit this file!
It is by default added to .gitignore
for you, but you should always take
care you are not accidentally sharing this file.
cp config/secrets.toml.template config/secrets.toml
Open the new secrets.toml
file in your preferred editor, and then navigate
to the GroupMe Bots page. Then, on the bots
page, create a new bot. For this bot's group, select the new chat you made
above. Name can be whatever you like, and you can leave the other fields blank.
Click submit, and retrieve your Bot ID
and Group ID
from the bots page. Put
these in your secrets.toml
under the groupme_bots
section, with your
Group ID
serving as the key and the Bot ID
serving as the value (which must
be in quotes).
For example, if your bot ID is 456
, and your group ID is 789
, your
secrets.toml
needs to contain the following
[groupme_bots]
789 = "456"
Note that other plugins may require additional secrets,
and that image uploads (namely with the !seychelles
plugin), require an
imgur client ID as well. You can skip this if you will not be using the
upload_image
function in the util
module, but if you will be uploading
images, log-in to Imgur and
register a new Application. Name
the application Rollbot or something similar, tick the box for Anonymous
usage without authorization, and fill in dummy values for any remaining
fields. Click submit, and put the Client ID
you are given on the next page
(which can also be looked up from Account Settings > Applications) into
your secrets.toml
, as the value for imgur_client_id
.
That's it for secrets!
Save the file and move on to deciding if you want to do your local execution
and/or development with or without docker
.
Run ./rollbot-docker.sh run
or manually run
docker build -t rollbot3:latest .
docker run -p6070:6070 --name rollbot3-instance -d rollbot3
You can run ./rollbot-docker.sh clean
to tear down the container.
This requires Python 3.7 to be installed on your machine. The use of a Python virtual environment is recommended, and so you should run the following
python3 -mvenv .venv
. .venv/bin/activate
pip install -r requirements.txt
To leave the virtual environment, simply run deactivate
, and when
you want to run the project again, you need only run . .venv/bin/activate
.
To launch rollbot run ./rollbot-local.sh
or cd
into src/
and run ROLLBOT_CFG_DIR=../config python3 app.py
, stopping
the execution with Ctrl-C
.
Please keep new plugin branches to the scheme feature/name-of-plugin
where possible. All work must be done on either a branch or a fork
of the repository, and must go through the pull request process.
If you do not have Python 3.7.1 (or later) available, or want to develop using docker locally, you
can make use of the rollbot-docker.sh
script. You will need to run this as root
(preferably with
sudo
), or as some user capable of using docker. If you are not running this script as root
, and
instead have a different local docker user, you will need to export FORCE_NOROOT=*
before running
the script.
You can run ./rollbot-docker.sh help
to see a full list of options. The most useful are run
and
clean
. To build the rollbot3:latest
image and deploy it to a docker container called
rollbot3-instance
on your local machine, simply run
./rollbot-docker.sh run
This will also blow away any existing container called rollbot3-instance
before building the new
image and container. If you would just like to kill and remove existing containers with that name,
without starting a new one, you can run
./rollbot-docker.sh clean
In general, your development loop will probably look something like, modify your plugin, run
./rollbot-docker.sh run
, and repeat. When you are all done, you can use ./rollbot-docker.sh clean
to remove the lingering container on your system.
Once you have a local server up on http://localhost:6070/rollbot
, point your REST client of choice
(my personal recommendation is Insomnia) at that address. Creat a new POST
request, of JSON
type (that is, your Content-Type
should be application/json
). Then, set the body
of this POST
to be
{
"text": "!echo Hello",
"group_id": "your-group-id",
"attachments": [],
"avatar_url": "https://i.groupme.com/123456789",
"created_at": 1302623328,
"id": "1234567890",
"name": "Insomnia",
"sender_id": "1",
"sender_type": "user",
"source_guid": "GUID",
"system": false,
"user_id": "1234567890"
}
The first two options, text
and group_id
will need to be modified. Set the value of group_id
to
the group ID you found and put into your secrets.toml
above. Then, click run! Or however your REST
client sends the request. If you have everything set up correctly, your phone should buzz and you
should receive a message in your bot testing chat you set up before, from the chatbot you added to it,
responding to a !echo Hello
command. Now, change the value of text
in the body of your request to
be whatever message you would like to simulate sending, and you should be able to get the hang of how
you can test your local instance of rollbot.
The quickstart for creating a new plugin is to determine a name for the plugin, say, my_cool_plugin
,
and run
./mkplugin my_cool_plugin
This script will generate a file at src/plugins/my_cool_plugin.py
containing (approximately)
from rollbot import as_plugin
@as_plugin
def my_cool_plugin():
return "Hello, world!"
The script also adds an import plugins.my_cool_plugin
to src/plugins/__init__.py
, so if you are
reverting what this script did, remember to remove this import from that file. Only plugins imported
in that top level module file will be available for the application, so if creating a plugin manually,
you will need to add an import to that file.
The above script is the most basic possible rollbot plugin, which will simply respond with
Hello, world!
when it receives a message starting with !my_cool_plugin
. The actual wiring of
the plugin is handled by the as_plugin
decorator, which performs all of the following:
as_plugin
, which is detailed below.RollbotResponse
and convert them to strings, before wrapping them in a RollbotResponse
with default settings, which
is detailed below.RollbotPlugin
extension class which overrides the on_command
method to call
your plugin function appropriately, and returns this class from the decorator, effectively assigning
it to the my_cool_plugin
variable instead of your plugin function, which is what allows your
plugin to be found dynamically after just importing the plugin moduleThe rollbot.plugins.decorators
module exports decorators that can be used for specific additional
functionality on functional commands. as_plugin
and with_help
are re-exported by rollbot
for
convenience, but other tools are left in this decorators submodule. All of these decorators should be
applied after as_plugin
.
with_startup
- attach a function to a command to override the RollbotPlugin.on_start
functionwith_shutdown
- the same as with_startup
, but for the RollbotPlugin.on_shutdown
functionrequire_min_args
- enforce a minimum number of arguments in the messagerequire_args
- enforce an exact number of arguments in the messageThe rollbot.plugins.injection
module exports many dependency injection tools for your
plugins. If you are using the as_plugin
decorator, you can annotate the arguments of your
function to have these values injected at runtime.
Message
- will receive the RollbotMessage
triggering the commandBot
- the Rollbot
instance executing the commandLogger
- the logger the command should useArgList
- the argument list, resulting from calling RollbotMessage.arg_list
Arg(n, conversion=c, fail_msg=m)
- will receive the argument at index n
, converted by
c
(which can be omitted if a string is desired), and will fail the command if the
conversion fails with a ValueError
and instead use the failure message m
in the response (which itself will be formatted with the actual value of the argument)Config(key=k)
- will receive the configuration associated with k
, or the root confiuration
dictionary if k
is not provided or is None
Database
- will receive the SQLAlchemy database session scope, but it is preferred to
use one of the other database-lookup types when possible
Singleton(cls)
- will receive the proper singleton for this execution of the given
cls
, which itself must be annotated with either as_group_singleton
or as_sender_singleton
.
Singleton(cls).by(fn)
- will execute fn
(a function with its own dependencies)
to perform the querySingletone(cls).by_all(fn)
- works same as Singleton.by
but fn
is instead
expected to return an iterable of keys, and all singletons will be looked upQuery(cls)
- will receive the contents of the table of the SQLAlchemy model class cls
Query(cls).filter(fn)
- filters the Query
by the filter returned by fn
(a function
with its own dependencies), which can be chained as Query.filter().filter()...
Lazy(a)
- will receive an object that, when Lazy.get
is called, will return the result of the
injection a
, delaying computation until this point, and only calculating the value on the first
call to get
Additionally, as a legacy feature, plugin arguments can use specific names to request specific dependencies. New plugins should not use this system, but the argument names and name patterns are:
msg
is the RollbotMessage triggering the commanddb
is the SQLAlchemy database session scopelog
is the command's loggerbot
is the Rollbot instance running the commanddata.*
is supplied the group singleton of the annotated data type.*cfg
is supplied the configuration associated with the annotated key (as a string)TODO
Further docs to come! Good luck!
Once you are confident your plugin is functional, push your code to remote with the following, again
replacing my-awesome-branch
with your chosen branch name.
git push -u origin feature/my-awesome-branch
Then, open a Pull Request, shoot me a message, and I'll take it from there!