autocycle: more checks

autocycle: more checks

Former-commit-id: f73fddb35147ff617b3c904523db37a2b7fedb26 [formerly 143f3bedc457522ba274fc7e9db1262b64eff4eb]
Former-commit-id: 4026dbed3aebd19870559b747516a3f9e79bc843

cycleNeeded = (source, destination, arg) =>
  -- Don't care about our own events
  if source.nick == @config.nick
    return
  -- Check if we are the last nick in the channel
  counter = 0
  unless @channels[destination]
    return
  unless @channels[destination].nicks
    return
  for nick, meta in pairs @channels[destination].nicks
    if nick == @config.nick
      -- Check if we have op
      for m in *meta.modes
        if m == 'o'
          return
    unless nick == @config.nick or nick == source.nick
      counter += 1

  if counter == 0
    @Log 'info', 'Cycling opless channel %s', destination
    @Part(destination)
    @Join(destination)

{
  PART: {
    cycleNeeded
  }
  QUIT: {
    cycleNeeded
  }
}

cycleNeeded = (source, destination, arg) =>
  -- Don't care about our own events
  if source.nick == @config.nick
    return
  -- Check if we are the last nick in the channel
  counter = 0
  for nick, meta in pairs @channels[destination].nicks
    if nick == @config.nick
      -- Check if we have op
      for m in *meta.modes
        if m == 'o'
          return
    unless nick == @config.nick or nick == source.nick
      counter += 1

  if counter == 0
    @Log 'info', 'Cycling opless channel %s', destination
    @Part(destination)
    @Join(destination)

{
  PART: {
    cycleNeeded
  }
  QUIT: {
    cycleNeeded
  }
}


gay: use util. fabulous alias

gay: use util. fabulous alias

Former-commit-id: 01e549e335715628b4bf8e5f0828280a2add8481
Former-commit-id: 566958c2e8a14d65285682808a5c8b1b62facbef

{:color, :utf8} = require'util'
FABULOUS_COLORS = {4, 7, 9, 10, 12, 13, 6}

i = 0

gayify = (s) ->
  if s == "" return ""
  s\gsub utf8.pattern, (c) ->
    ret = color(c, FABULOUS_COLORS[i + 1])
    i = (i + 1) % #FABULOUS_COLORS
    return ret

gaywordify = (s) ->
  if s == "" return ""
  ivar2.util.translateWords s, (c) ->
    ret = color(c, FABULOUS_COLORS[i + 1])
    i = (i + 1) % #FABULOUS_COLORS
    return ret

PRIVMSG:
  '^%pgay (.+)$': (source, destination, arg) =>
      say gayify arg
  '^%pgaywords (.+)$': (source, destination, arg) =>
      say gaywordify arg
  '^%pfabulous (.+)$': (source, destination, arg) =>
      say gaywordify arg

FABULOUS_COLORS = {4, 7, 9, 10, 12, 13, 6}

i = 0

gayify = (s) ->
  if s == "" return ""
  s\gsub "[%z\1-\127\194-\244][\128-\191]*", (c) ->
    ret = string.format("\03%02d%s", FABULOUS_COLORS[i + 1], c)
    i = (i + 1) % #FABULOUS_COLORS
    return ret

gaywordify = (s) ->
  if s == "" return ""
  ivar2.util.translateWords s, (c) ->
    ret = string.format("\03%02d%s", FABULOUS_COLORS[i + 1], c)
    i = (i + 1) % #FABULOUS_COLORS
    return ret

PRIVMSG:
  '^%pgay (.+)$': (source, destination, arg) =>
      say gayify arg
  '^%pgaywords (.+)$': (source, destination, arg) =>
      say gaywordify arg


Fix test

Fix test

-- include redx path
package.path = package.path .. ";lua/src/lib/?.lua;lua/src/lib/plugins/?.lua"

url = require 'socket.url'
inspect = require 'inspect'
base64 = require 'base64'
library = require 'library'  -- from redx

-- inspect module inserted into global env
_G.inspect = inspect

-- library module inserted into global env
_G.library = library

-- fake ngx module inserted into global env
_G.ngx = {
    DEBUG: 'DEBUG'
    NOTICE: 'NOTICE'
    WARN: 'WARN'
    ERR: 'ERROR'
    header: {}
    log: (lvl, msg) ->
        print(lvl .. ": " .. msg)
    req: {
        clear_header: (h) ->
    }
}

-- load plugin
plugin = require "stickiness"

describe "stickiness plugin", ->
    randomize!

    -- initialize plugin settings
    settings = {
        COOKIE: 'session'
    }

    new_session = (frontend, backend, servers) ->
        m = math.huge
        for k in pairs(servers)
            m = math.min(k, m)
        return {
            frontend: frontend
            backend: backend
            servers: servers
            server: servers[m].address
            config: {
                shinyapps_auth: users
            }
        }

    new_request = (u, cookie=nil) ->
        return {
            req: {
                header: headers
                parsed_url: url.parse(u)
            }
            cookies: {
                session: cookie
            }
        }

    it "should set sticky session cookie", () ->

        -- construct request
        request = new_request('http://example.com/foo/derp')

        -- construct session
        session = new_session('example.com/foo/', 12345, {{address: 'fake-server:8000'}})

        response = plugin.post(request, session, settings)

        cookie = "session=#{url.escape(base64.encode('fake-server:8000'))}; Path=/foo/; HttpOnly; SameSite=None; Secure"
        assert.are.same(ngx.header['Set-Cookie'], cookie)

    it "should use existing sticky session cookie if its valid", () ->

        -- construct request
        request = new_request('http://example.com/foo/bar', base64.encode('fake-server:8000'))

        -- construct a session
        session = new_session('example.com/', 12345, {{address: 'fake-server:8000'}, {address: 'another-fake-server:8000'}})

        response = plugin.post(request, session, settings)
        assert.are.same(ngx.header['Set-Cookie'], nil)

    it "should use valid servers in the sticky session cookie", () ->

        -- construct request
        request = new_request('http://example.com/', base64.encode('fake-server:8000'))

        -- construct session
        session = new_session('example.com', 12345, {{address: 'fake-server:8000'}})

        result = plugin.balance(request, session, settings)
        assert.are.same({address: 'fake-server:8000'}, result)

    it "should ignore invalid values in the session cookie", () ->

        -- construct request
        request = new_request('http://example.com/', "garbage cookie")

        -- construct session
        session = new_session('example.com', 12345, {{address: 'fake-server:8000'}})

        result = plugin.balance(request, session, settings)
        assert.are.same({{address: 'fake-server:8000'}}, result)
        assert.are.same(request.cookies['session'], nil)

    it "should ignore invalid servers in the sticky session cookie", () ->

        -- construct a request
        request = new_request('http://example.com/', base64.encode('another-fake-server:8000'))

        -- construct a session
        session = new_session('example.com', 12345, {{address: 'fake-server:8000'}})

        result = plugin.balance(request, session, settings)
        assert.are.same({{address: 'fake-server:8000'}}, result)
        assert.are.same(request.cookies['session'], nil)

-- include redx path
package.path = package.path .. ";lua/src/lib/?.lua;lua/src/lib/plugins/?.lua"

url = require 'socket.url'
inspect = require 'inspect'
base64 = require 'base64'
library = require 'library'  -- from redx

-- inspect module inserted into global env
_G.inspect = inspect

-- library module inserted into global env
_G.library = library

-- fake ngx module inserted into global env
_G.ngx = {
    DEBUG: 'DEBUG'
    NOTICE: 'NOTICE'
    WARN: 'WARN'
    ERR: 'ERROR'
    header: {}
    log: (lvl, msg) ->
        print(lvl .. ": " .. msg)
    req: {
        clear_header: (h) ->
    }
}

-- load plugin
plugin = require "stickiness"

describe "stickiness plugin", ->
    randomize!

    -- initialize plugin settings
    settings = {
        COOKIE: 'session'
    }

    new_session = (frontend, backend, servers) ->
        m = math.huge
        for k in pairs(servers)
            m = math.min(k, m)
        return {
            frontend: frontend
            backend: backend
            servers: servers
            server: servers[m].address
            config: {
                shinyapps_auth: users
            }
        }

    new_request = (u, cookie=nil) ->
        return {
            req: {
                header: headers
                parsed_url: url.parse(u)
            }
            cookies: {
                session: cookie
            }
        }

    it "should set sticky session cookie", () ->

        -- construct request
        request = new_request('http://example.com/foo/derp')

        -- construct session
        session = new_session('example.com/foo/', 12345, {{address: 'fake-server:8000'}})

        response = plugin.post(request, session, settings)

        cookie = "session=#{url.escape(base64.encode('fake-server:8000'))}; Path=/foo/; HttpOnly"
        assert.are.same(ngx.header['Set-Cookie'], cookie)

    it "should use existing sticky session cookie if its valid", () ->

        -- construct request
        request = new_request('http://example.com/foo/bar', base64.encode('fake-server:8000'))

        -- construct a session
        session = new_session('example.com/', 12345, {{address: 'fake-server:8000'}, {address: 'another-fake-server:8000'}})

        response = plugin.post(request, session, settings)
        assert.are.same(ngx.header['Set-Cookie'], nil)

    it "should use valid servers in the sticky session cookie", () ->

        -- construct request
        request = new_request('http://example.com/', base64.encode('fake-server:8000'))

        -- construct session
        session = new_session('example.com', 12345, {{address: 'fake-server:8000'}})

        result = plugin.balance(request, session, settings)
        assert.are.same({address: 'fake-server:8000'}, result)

    it "should ignore invalid values in the session cookie", () ->

        -- construct request
        request = new_request('http://example.com/', "garbage cookie")

        -- construct session
        session = new_session('example.com', 12345, {{address: 'fake-server:8000'}})

        result = plugin.balance(request, session, settings)
        assert.are.same({{address: 'fake-server:8000'}}, result)
        assert.are.same(request.cookies['session'], nil)

    it "should ignore invalid servers in the sticky session cookie", () ->

        -- construct a request
        request = new_request('http://example.com/', base64.encode('another-fake-server:8000'))

        -- construct a session
        session = new_session('example.com', 12345, {{address: 'fake-server:8000'}})

        result = plugin.balance(request, session, settings)
        assert.are.same({{address: 'fake-server:8000'}}, result)
        assert.are.same(request.cookies['session'], nil)