{"id":23498030,"url":"https://github.com/freedomben/nexy","last_synced_at":"2025-04-15T15:38:38.627Z","repository":{"id":38181638,"uuid":"162532595","full_name":"FreedomBen/nexy","owner":"FreedomBen","description":"Source code for nexy, the Simple Nexus Slack bot","archived":false,"fork":false,"pushed_at":"2024-03-19T00:12:16.000Z","size":96,"stargazers_count":4,"open_issues_count":3,"forks_count":1,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-03-28T22:01:36.387Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Ruby","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/FreedomBen.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2018-12-20T05:48:47.000Z","updated_at":"2022-03-03T18:22:03.000Z","dependencies_parsed_at":"2023-01-19T14:17:23.386Z","dependency_job_id":null,"html_url":"https://github.com/FreedomBen/nexy","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/FreedomBen%2Fnexy","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/FreedomBen%2Fnexy/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/FreedomBen%2Fnexy/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/FreedomBen%2Fnexy/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/FreedomBen","download_url":"https://codeload.github.com/FreedomBen/nexy/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":249099762,"owners_count":21212720,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-12-25T05:17:57.303Z","updated_at":"2025-04-15T15:38:38.606Z","avatar_url":"https://github.com/FreedomBen.png","language":"Ruby","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Nexy\n\n## What does Nexy do?\n\nCurrently Nexy has the following skills:\n\n1. Looking up words in the dictionary (Merriam-Webster.  Requires API key)\n1. Translating Jira numbers to Jira ticket links\n1. Fetching dad jokes\n1. Looking up bitcoin and other cryptocurrency values (in dollars)\n\n## How do I start up Nexy for development?\n\n* Add your slack token to `slackbot-frd.conf` in the provided spot (or set it as an env var, which is recommended for production environments).  For more information see [the slackbot_frd documentation](https://github.com/FreedomBen/slackbot_frd#prestantious--eximious--how-do-i-start)\n* Add your Merriam Webster dictionary keys to `slackbot-frd.conf` (or the env var) if you want to use the dictionary bot\n* run `bundle install`\n* run `slackbot-frd start` from the top-level directory\n\n## Can I send pull requests?\n\nPlease do!\n\n## What framework does this use?\n\nNexy uses [slackbot_frd](https://github.com/FreedomBen/slackbot_frd)\n\n## Running in production\n\n### Provisioning the VM\n\nAny VM service provider will do.  Nexy runs in docker, and has been hosted on Digital Ocean and AWS EC2 at various times.  The important part is that you install docker on your base image.  Once docker is installed, clone this repo:\n\n```bash\ngit clone https://github.com/FreedomBen/nexy.git\n```\n\nYou will also probably want to install some additional tools on the system, such as `tmux`\n(which is useful for maintaining the session after the SSH connection is closed.\nInstructions in this guide will assume you are using tmux, with the provided `tmux.conf`\nfile installed at `$HOME/.tmux.conf` (you can use the script `./dotfiles/update-dot-files.sh`\nto do this for you, but be advised it will stomp on existing files (which you probably don't\nwant to do on your dev machine, only on the nexy server)).\n\n### Building/Starting the instance\n\n#### Building\n\nThere is a handy script located at `scripts/build.sh` that will build you an image of nexy that you can then run with the other script (see [Starting](#starting)).  Call it from the root of the project like this:\n\n```bash\n./scripts/build.sh\n```\n\nAlternatively you can build it manually from the project root by running:\n\n```bash\ndocker build -t nexy .\n```\n\nThis builds an image named \"nexy\".  If you give it a different name, you'll need to make note of that for when you run the image as a container.\n\n#### Starting\n\n_NOTE: The tmux portion is optional, but recommended_\n\nIf you're not in a `tmux` session yet, kick one off:\n\n```bash\ntmux\n```\n\nOr if one already exists, find it and attach to it:\n\n```bash\ntmux ls           # list current sessions\ntmux at -t \u003cnum\u003e  # attach to session \u003cnum\u003e e.g:  0\n```\n\nCheck out the [tmux](#tmux-tips) section for a quick rundown of common tmux things that are handy.\n\nOnce the image is [built](#building), you can run it with the handy script:\n\n```bash\n./scripts/run-container.sh\n```\n\nor manually using:\n\n```bash\ndocker run -it --rm --name nexy nexy bash\n```\n\n_NOTE:  The reason we are calling `bash` in the container is because currently the decryption key to unlock the secrets must be typed in manually._\n\nOnce the container is running, use the `start` alias to kick things off.  It will prompt you for the decryption key (password) which you will need to enter:\n\n```bash\n$ start\nEnter password:\n```\n\nNexy should now be running!  If you're curious about implementation, read on for some explanation.\n\nThe `start` alias is defined in the `Dockerfile` as a shortcut to calling:\n\n```bash\n/app/scripts/start-bots.sh\n```\n\nThe `scripts/start-bots.sh` script will call `aescrypt` to decrypt the secrets file and source the contents into the current shell, then start `slackbot-frd` for you.  All it does is call:\n\n```bash\n. \u003c(aescrypt -d nexy.aes -o -) || echo 'Doh password was wrong'\nslackbot-frd start\n```\n\n##### Restarts and ping/pong\n\nThe underlying [slackbot_frd](https://github.com/FreedomBen/slackbot_frd) library uses ping/pong\nsignals to ensure that the connection is still up.  This is good because every once in a while\nslack will stop responding on the other end, but the socket is never closed.  Without a ping/pong\ncheck, nexy will happily continue running thinking everything is fine, when in fact it is not.\n\nIf the slack server fails to answer the \"ping\" message with a \"pong\" after a few seconds,\n[slackbot_frd](https://github.com/FreedomBen/slackbot_frd) will tear down the connection and\nrestart it.  This has successfully been done for years now in production.\n\nOccasionally however, something strange will happen and you will need to manually restart nexy.\nWhen this occurs, simply navigate to the running window (in tmux for example) and Ctrl+C the instance,\nthen restart it with normal procedure of running `start`\n\n#### Deploying changes/Updating the source code\n\nDeploying changes is as simple as SSHing in to the VM, then change to the code directory and run:\n\n```bash\ngit pull --rebase\n./scripts/build.sh\n```\n\nThen attach to the tmux session and restart the container:\n\n```bash\ntmux at  # if not already attached\n# \u003cCtrl+c\u003e in running window\n./scripts/run-container.sh\nstart\n# Enter password\n```\n\n#### tmux tips\n\nStart a new session:\n\n```bash\ntmux\n```\n\nAttach to existing session:\n\n```bash\ntmux ls           # list current sessions\ntmux at -t \u003cnum\u003e  # attach to session \u003cnum\u003e e.g:  0\n```\n\nDetach from session:\n\n```\n\u003cCtrl+b\u003e d\n```\n\nSplit current pane horizontally:\n\n```\n\u003cCtrl+b\u003e\u003cCtrl+d\u003e\n```\n\nSplit current pane vertically:\n\n```\n\u003cCtrl+b\u003e\u003cCtrl+s\u003e\n```\n\nNavigate panes:\n\n```\n\u003cCtrl+b\u003e h   # h, j, k, l for left, up, down, or right (like vim)\n```\n\n### Modifying the secrets file `nexy.aes`:\n\nIf you need to add, update, or delete a value in the secrets file, this is not hard.  It does require [aescrypt](https://www.aescrypt.com/) CLI tool to be installed on your machine.  You can peek at the `Dockerfile` for hints on how to install it.  On Fedora, you just need to install dependencies:\n\n```bash\nsudo dnf install unzip glibc glibc-devel glibc-static\n```\n\nThen pull down, build, and install:\n\n```bash\ncd ~   # or wherever you prefer\nwget https://github.com/FreedomBen/aescrypt/archive/master.zip\nunzip master.zip\ncd aescrypt-master/linux/src\nmake\nsudo make install\n```\n\nNow decrypt the secrets file\n\n```bash\naescrypt -d nexy.aes\n```\n\nEnter the decryption key when prompted for the password.  Once decrypted open the new file `nexy` in the editor of your choice and make your modifications.\n\n*IMPORTANT:  You must stick to legal bash syntax since the contents of this file are sourced into a bash shell in the nexy container*\n\nNow re-encrypt the file, being very careful not to fat-finger the key:\n\n```bash\naescrypt -e nexy\n```\n\n`rm` the plaintext file and commit your updated version to the repo.\n\n_TIP:  If you just want to view the contents of the file, you can print it to the terminal with:_\n\n```bash\naescrypt -d -o - nexy.aes\n```\n\n_Keep in mind tho that the contents will stick around in the tmux buffer so be discriminating about where you do this._\n\n### Periodic Maintenance\n\n#### Installing updates\n\nIf running on Amazon Linux, Red Hat, CentOS, or other related distro, use:\n\n    sudo yum update\n\n*NOTE:* **If the update installs a new docker engine (which it does from time to time), it will kill all running docker containers which includes nexy, and she'll need to be restarted again**\n\n#### Cleaning up docker artifacts\n\nPeriodically, after starting/stopping docker containers, you may want to clean up artifacts left by docker.  This will prevent the disk from filling up.  There are a few things you should do:\n\n1.  Cleanup unlabeled images (often build artifacts)\n\n```bash\ndocker rmi $(docker images | grep -iE '^\u003cnone\u003e' | awk '{print $3}' | xargs)\n```\n\n1.  Cleanup old containers (nexy containers shouldn't accumulate, but still good to check)\n\n#### Scaling\n\n_Note:  This is a glimpse into the distant future and isn't relevant now, but might be at some point, so I've included it here as part of my brain dump_\n\nCurrently a single angel bot instance more than meets the demand at Instructure.  In the future it's possible that this may change.  Due to underlying libraries, angel runs on a single thread, and there isn't really a vertical scaling option.  Fortunately I foresee a few strategies for scalining horizontally, which is the better way to scale anyway.\n\n1.  Multiple instances of nexy on the same EC2 instance\n1.  Multiple EC2 instances running one or more instances of nexy\n\nThe way it is currently, running _n_ instances of angel bot will result in _n_ responses to every trigger.  This is obviously terrible.  To correct this, there are a couple strategies to choose from (ordered by what sound like the best options to me currently):\n\n1.  Have each instance only answer some non-intersecting subset of channels:  E.g.:  Instance 0 is listening in channels a, b, and c (busy channels) while Instance 1 listens in all other channels\n    - To accomplish this, you will need to modify the bot code to check for the appropriate channel.  There a couple of ways to do this.  See `greeting-bot.rb` for a good example (it uses slackbot_frd to do the filtering rather than checking `channel == 'mychannel'`.  If using a subset tho, I don't think currently works with slackbot_frd so you might need to do something like `if %w[c1, c2].include?(channel)`\n1.  Have each instance run a non-intersecting subset of bots.  E.g. Instance 0 runs the gerrit-jira translator (main source of traffic) and instance 1 runs all the others\n\n_NOTE:  The scripts in `scripts/*` will need to be modified to use different container name based on the instance, because currently if starting multiple instances on the same docker daemon, there will be a name conflict_\n\n\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffreedomben%2Fnexy","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffreedomben%2Fnexy","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffreedomben%2Fnexy/lists"}