Write DiscordBot to Spreadsheets Write in Ruby and run with Docker

Introduction

This article is the 17th day article of Hamee Advent Calendar 2020.

As a hobby, I play a certain dangerous ☆ game, and at the end of every month, I mainly enjoy the event where 30 players form a team and compete for ranking. The top ranking teams play on Discord while keeping in touch with each other, but since they only interact by chat, if there are as many as 30 players, the information cannot be gathered and the event cannot proceed smoothly. there is. To solve that, I created a bot that writes to Google Spreadsheets from Discord chat content. However, since it is no longer used from this month, it will be a memorial service in this article.

Preparation

Bot token is required for DiscordBot development. I wrote an article before, so please refer to this (this time it will work with Ruby).

-Try running discord bot with python

You also need the Spreadsheets API credentials to write to Spreadsheet. Please refer to ** [Google Sheets API Settings] ** in this article.

-Manipulate Sheets Using Google Sheets API

It runs on the Docker container, but I will omit Docker.

contents

Since I made it in about 2 days, there are many parts that are not cool.

The prepared file and structure looks like this.

tree


.
├── Dockerfile
├── Gemfile
├── Gemfile.lock
└── source
    ├── .env
    ├── bot.rb
    └── credentials.json

Spreadsheet

Prepare the following sheet as a bot that writes in column C of the row of the person who spoke

A B C
1 252398827 Mr. A
2 261223322 Mr. B
3 348710907 Mr. C

Dockerfile

Dockerfile


FROM ruby:2.6.5

ENV APP_HOME /home/source

RUN mkdir -p $APP_HOME
WORKDIR $APP_HOME
ADD Gemfile Gemfile
ADD Gemfile.lock Gemfile.lock
ADD ./source ./

RUN bundle install

CMD ["bundle", "exec", "ruby", "bot.rb"]

Build and run this Dockerfile

Gemfile

Gemfile


source 'https://rubygems.org'

gem 'dotenv'
gem 'discordrb'
gem 'google_drive'

credentials.json

Place the one prepared in the above preparation as it is.

bot.rb

I'm not thinking about errors throughout.

Spreadsheets part

bot.rb


require "google/apis/sheets_v4"
require "googleauth/stores/file_token_store"
require "fileutils"

Dotenv.load

class Spreadsheet
  OOB_URI = 'urn:ietf:wg:oauth:2.0:oob'.freeze
  APPLICATION_NAME = 'MyBot'.freeze
  CREDENTIALS_PATH = 'credentials.json'.freeze
  TOKEN_PATH = 'token.yaml'.freeze
  SCOPE = Google::Apis::SheetsV4::AUTH_SPREADSHEETS
  ID = ENV['SHEAT_ID']

  attr_accessor :service

  def initialize
    @service = Google::Apis::SheetsV4::SheetsService.new
    @service.client_options.application_name = APPLICATION_NAME
    @service.authorization = authorize
  end

  def authorize
    client_id = Google::Auth::ClientId.from_file CREDENTIALS_PATH
    token_store = Google::Auth::Stores::FileTokenStore.new file: TOKEN_PATH
    authorizer = Google::Auth::UserAuthorizer.new client_id, SCOPE, token_store
    user_id = "default"
    credentials = authorizer.get_credentials user_id
    if credentials.nil?
      url = authorizer.get_authorization_url base_url: OOB_URI
      puts "Open the following URL in the browser and enter the " \
           "resulting code after authorization:\n" + url
      code = gets
      credentials = authorizer.get_and_store_credentials_from_code(
        user_id: user_id, code: code, base_url: OOB_URI
      )
    end
    credentials
  end

  def read(range)
    response = service.get_spreadsheet_values ID, range
    response.values
  end
  
  def write(range, value)
    data = Google::Apis::SheetsV4::ValueRange.new
    data.major_dimension = 'ROWS'
    data.range = range
    data.values = [[value]]
    options = {
      value_input_option: 'RAW'
    }

    response_write = service.update_spreadsheet_value ID, range, data, options
    response_write.updated_cells
  end
end

Discordbot part

bot.rb


require 'discordrb'
require 'dotenv'

Dotenv.load

class MyBot
  attr_accessor :bot, :spreadsheet

  def initialize
    @bot = Discordrb::Commands::CommandBot.new client_id: ENV['CLIENT_ID'], token: ENV['BOT_TOKEN']
    @spreadsheet = Spreadsheet.new
  end

  def start
    settings

    @bot.run
  end
  
  def get_user_row(user_id)
    a = @spreadsheet.read('A:A')
    (a.find_index [user_id.to_s]) + 1
  end

  def settings
    @bot.message contains: /^[1-3]$/ do |event|
      num = event.content
      user_row = get_user_row event.user.id
      @spreadsheet.write "C#{user_row}", num
    end
  end

end

bot = MyBot.new
bot.start

Clog point

Actually, there is a defect in the Dockerfile mentioned earlier, and when I start it, the following error is displayed.

/usr/local/bundle/gems/ffi-1.13.1/lib/ffi/library.rb:145:in `block in ffi_lib': Could not open library 'sodium': sodium: cannot open shared object file: No such file or directory. (LoadError)
Could not open library 'libsodium.so': libsodium.so: cannot open shared object file: No such file or directory

It seems that the library called libsodium is not enough, but even if I try to google it, I do not know who it is.

After all, it was properly written as a dependent file in discordrb README, and I just missed it. Since it wasn't explicitly stated in other blogs that explain discordrb, it was an example of getting stuck when trying to make only the basic part with copy and paste. Solved by adding the following description to the Dockerfile.

Dockerfile


RUN apt-get update -y && apt-get install -y libsodium-dev

in conclusion

At the end of November, the above bot was in operation. For various reasons this month, we plan to recreate the bot with node.js to expand its functionality and are currently under development. Personally, I'm happy to be able to develop a bot with Ruby, and it's good that my child is working hard to see the bot running.

Recommended Posts

Write DiscordBot to Spreadsheets Write in Ruby and run with Docker
Create jupyter notebook with Docker and run ruby
Write keys and values in Ruby
Run logstash with Docker and try uploading data to Elastic Cloud
How to run a job with docker login in AWS batch
Convert JSON to TSV and TSV to JSON with Ruby
Try to link Ruby and Java with Dapr
Run Pico with docker
Run Payara with Docker
[Ruby on Rails] How to write enum in Japanese
Converting TSV files to CSV files (with BOM) in Ruby
How to handle TSV files and CSV files in Ruby
Run Mosquitto with Docker and try WebSocket communication with MQTT
How to launch Swagger UI and Swagger Editor in Docker
Link Docker log to AWS CloudWatch and monitor in real time with VS Code
Let's write how to make API with SpringBoot + Docker from 0
Run TAO Core with Docker
Write class inheritance in Ruby
Make Docker confusing with Pokemon and make it easier to attach
Run Rails whenever with docker
When you want to explicitly write OR or AND with ransack
Build a Node-RED environment with Docker to move and understand
With podman in docker, everyone wants to get along and use docker on a shared computer
[Ruby] How to write blocks
How to deal with different versions of rbenv and Ruby
Easily convert Java application to Docker container with Jib ~ Build with gradle and register in local repository
I tried to write code like a type declaration in Ruby
Offline real-time how to write F03 ruby and C implementation example
AtCoder ARC 081 C hash to solve in Ruby, Perl and Java
How to write ruby if in one line Summary by beginner
Sample to read and write LibreOffice Calc fods file in JRuby 2021
How to get and add data from Firebase Firestore in Ruby
Sample to read and write LibreOffice Calc fods file in Java 2021
Things to remember and concepts in the Ruby on Rails tutorial
How to encrypt and decrypt with RSA public key in Java
Run lambda with custom docker image
Run LibreOffice Basic macros in Docker
How to run JUnit in Eclipse
Try to implement Yubaba in Ruby
[Rails] How to write in Japanese
How to run Ant in Gradle
How to run JavaFX on Docker
Hello World with Docker and C
[Ruby] then keyword and case in
How to install Bootstrap in Ruby
Make JupyterLab run anywhere with docker
Microservices With Docker and Cloud Performance
Update MySQL from 5.7 to 8.0 with Docker
How to start Camunda with Docker
[Ruby on Rails] How to log in with only your name and password using the gem devise
For the time being, run the war file delivered in Java with Docker
Wait for PostgreSQL to start with Docker and then start the WEB service
Starting with installing Docker on EC2 and running Yellowfin in a container
Sorting AtCoder ABC 111 C hashes to solve in Ruby, Perl and Java
How to execute with commands of normal development language in Docker development environment
[Firestore] Extract the collection with where condition in Ruby and delete the record
I tried to solve the tribonacci sequence problem in Ruby, with recursion.
Put Zabbix in Ubuntu with Docker and monitor Docker on the same host
How to build a Ruby on Rails development environment with Docker (Rails 6.x)
[Node.js express Docker] How to define Docker environment variables and load them with node.js
How to build a Ruby on Rails development environment with Docker (Rails 5.x)