cord-nvim 2.0.0-beta.13

🚀 The most extensible Discord Rich Presence plugin for Neovim, powered by Rust.
local async = require 'cord.core.async'
local logger = require 'cord.plugin.log'

local M = {}

function M:connect(path, retried)
  return async.wrap(function()
    if M.is_updating then
      logger.debug 'Operation canceled: Server is updating'
      return
    end

    self.status = 'connecting'
    logger.debug 'Connecting...'

    logger.debug('Pipe: ' .. path)
    M.client = require('cord.core.uv.pipe').new()
    local _, err = M.client:connect(path):get()

    if not err then
      self.status = 'connected'
      logger.debug 'Connected to pipe'
      return M:run():await()
    end

    if retried then error('Failed to connect to pipe: ' .. err, 0) end

    if err ~= 'ENOENT' and err ~= 'ECONNRESET' then
      if err == 'ECONNREFUSED' or err == 'ETIMEDOUT' then
        logger.debug 'Found stale pipe. Removing...'
        require('cord.core.uv.fs').unlink(path):get()
        goto spawn
      end

      error('Failed to connect to pipe: ' .. err, 0)
    end

    ::spawn::
    logger.debug 'Pipe not found. Spawning server executable...'

    local process = require('cord.server.spawn').spawn(self.config, path)
    local should_continue, retry = process:await()
    if not should_continue then return end

    logger.debug 'Server executable spawned'
    if retry then return M:connect(path):await() end
    M:connect(path, true):await()
  end)()
end

function M:run()
  return async.wrap(function()
    local EventSender = require 'cord.server.event.sender'
    local EventReceiver = require 'cord.server.event.receiver'
    M.tx = EventSender.new(M.client)
    M.rx = EventReceiver.new(M.client)

    M.rx:register(
      'ready',
      true,
      vim.schedule_wrap(function()
        self.status = 'ready'
        async.run(function()
          logger.info 'Connected to Discord'
          M.tx:initialize(self.config)

          local ActivityManager = require 'cord.plugin.activity.manager'
          local manager, err =
            ActivityManager.new({ tx = M.tx, config = self.config }):get()
          if not manager or err then
            self.status = 'disconnected'
            self.client:close()
            logger.error(err or 'Failed to initialize activity manager')
            return
          end

          M.client.on_close = vim.schedule_wrap(function()
            M.status = 'disconnected'
            if M.manager then M.manager:cleanup() end
            if self.config.hooks.on_disconnect then
              self.config.hooks.on_disconnect()
            end
          end)

          manager:run()
          M.manager = manager

          M.rx:register(
            'disconnect',
            false,
            vim.schedule_wrap(function()
              self.status = 'connected'
              M.manager:cleanup()
              if self.config.hooks.on_disconnect then
                self.config.hooks.on_disconnect()
              end

              if self.config.advanced.discord.reconnect.enabled then
                logger.info 'Reconnecting...'
              end

              M.rx:register(
                'ready',
                true,
                vim.schedule_wrap(function()
                  self.status = 'ready'
                  logger.info 'Connected to Discord'
                  M.manager:run()
                end)
              )
            end)
          )
        end)
      end)
    )

    logger.debug 'Server initialized'
    M.rx:run()
  end)()
end

function M:initialize(config)
  self.status = 'connecting'
  self.config = config or self.config
  async.run(function()
    logger.debug 'Initializing server...'

    local path = self.config.advanced.server.pipe_path
      or require('cord.plugin.constants').get_pipe_path()

    local _, err = M:connect(path):get()
    if err then
      self.status = 'disconnected'
      logger.error(err)
    end
  end)
end

function M:cleanup()
  if self.manager then self.manager:cleanup() end
  if self.client and not self.client:is_closing() then self.client:close() end
end

return M