<commit_before>--
-- piepie - bot framework for Mumble
--
-- Author: <NAME> <<EMAIL>>
-- License: MIT (see LICENSE)
--
--

-- TODO:  coroutines for fetching/returning data we do not yet have (comment/
--        texture hashes)

-- Global data
piepan.User.__index = piepan.User
piepan.Message.__index = piepan.Message
piepan.Channel.__index = piepan.Channel
piepan.Timer.__index = piepan.Timer

piepan.server = {}
piepan.args = {}
piepan.scripts = {}
piepan.users = {}
piepan.channels = {}
piepan.Thread.threads = {}

-- Local data
local functionLock = false
local hasSynced = false
local localUsers = {} -- table of users with the user's session ID as the key
local timers = {}

local native = {
    User = {
        kick = piepan.User.kick,
        moveTo = piepan.User.moveTo,
        ban = piepan.User.ban,
        send = piepan.User.send
    },
    Channel = {
        send = piepan.Channel.send
    },
    Timer = {
        new = piepan.Timer.new,
        cancel = piepan.Timer.cancel
    },
    Thread = {
        new = piepan.Thread.new
    },
    disconnect = piepan.disconnect
}

--
-- Script manager
--
function piepan._implLoadScript(filename, reload)
    assert(functionLock == false, "cannot call implementation functions")
    assert(type(filename) == "string", "filename must be a string")

    if piepan.scripts[filename] ~= nil and not reload then
        return true
    end
    local script, message = loadfile(filename)
    if script == nil then
        return false, message
    end
    local status, message = pcall(script)
    if status == false then
        return false, message
    end

    piepan.scripts[filename] = {
        onConnect = piepan.onConnect,
        onDisconnect = piepan.onDisconnect,
        onMessage = piepan.onMessage,
        onUserChange = piepan.onUserChange,
        onChannelChange = piepan.onChannelChange
    }
    piepan.onConnect = nil
    piepan.onDisconnect = nil
    piepan.onMessage = nil
    piepan.onUserChange = nil
    piepan.onChannelChange = nil

    return true
end

function piepan._implCall(name, arg)
    assert(type(name) == "string", "name must be a string")

    functionLock = true
    for _,script in pairs(piepan.scripts) do
        local func = script[name]
        if type(func) == "function" then
            status, message = pcall(func, arg)
            if not status then
                print ("Error: " .. message)
            end
        end
    end
    functionLock = false
end

--
-- Argument parsing
--
function piepan._implArgument(key, value)
    assert(type(key) ~= nil, "key cannot be nil")

    value = value or ""
    if piepan.args[key] == nil then
        piepan.args[key] = {value}
    else
        table.insert(piepan.args[key], value)
    end
end

--<commit_msg>Each script now has its own environment, which allows scripts to use globals safely<commit_after>--
-- piepie - bot framework for Mumble
--
-- Author: <NAME> <<EMAIL>>
-- License: MIT (see LICENSE)
--
--

-- TODO:  coroutines for fetching/returning data we do not yet have (comment/
--        texture hashes)

-- Global data
piepan.User.__index = piepan.User
piepan.Message.__index = piepan.Message
piepan.Channel.__index = piepan.Channel
piepan.Timer.__index = piepan.Timer

piepan.server = {}
piepan.args = {}
piepan.scripts = {}
piepan.users = {}
piepan.channels = {}
piepan.Thread.threads = {}
piepan.meta = {}

-- Local data
local functionLock = false
local hasSynced = false
local localUsers = {} -- table of users with the user's session ID as the key
local timers = {}

local native = {
    User = {
        kick = piepan.User.kick,
        moveTo = piepan.User.moveTo,
        ban = piepan.User.ban,
        send = piepan.User.send
    },
    Channel = {
        send = piepan.Channel.send
    },
    Timer = {
        new = piepan.Timer.new,
        cancel = piepan.Timer.cancel
    },
    Thread = {
        new = piepan.Thread.new
    },
    disconnect = piepan.disconnect
}

--
-- Script manager
--
function piepan._implLoadScript(filename, reload)
    assert(functionLock == false, "cannot call implementation functions")
    assert(type(filename) == "string", "filename must be a string")

    if piepan.scripts[filename] ~= nil and not reload then
        return true
    end
    local environment = {
        print = print,
        assert = assert,
        collectgarbage = collectgarbage,
        dofile = dofile,
        error = error,
        getmetatable = getmetatable,
        ipairs = ipairs,
        load = load,
        loadfile = loadfile,
        next = next,
        pairs = pairs,
        pcall = pcall,
        print = print,
        rawequal = rawequal,
        rawget = rawget,
        rawlen = rawlen,
        rawset = rawset,
        require = require,
        select = select,
        setmetatable = setmetatable,
        tonumber = tonumber,
        tostring = tostring,
        type = type,
        xpcall = xpcall,

        bit32 = bit32,
        coroutine = coroutine,
        debug = debug,
        io = io,
        math = math,
        os = os,
        package = package,
        string = string,
        table = table,

        piepan = {}
    }
    local script, message = loadfile(filename, "bt", environment)
    if script == nil then
        return false, message
    end
    local status, message = pcall(script)
    if status == false then
        return false, message
    end

    piepan.scripts[filename] = {
        environment = environment.piepan,
        onConnect = environment.piepan.onConnect,
        onDisconnect = environment.piepan.onDisconnect,
        onMessage = environment.piepan.onMessage,
        onUserChange = environment.piepan.onUserChange,
        onChannelChange = environment.piepan.onChannelChange
    }
    setmetatable(environment.piepan, piepan.meta)

    return true
end

function piepan._implCall(name, arg)
    assert(type(name) == "string", "name must be a string")

    functionLock = true
    for _,script in pairs(piepan.scripts) do
        local func = script[name]
        if type(func) == "function" then
            status, message = pcall(func, arg)
            if not status then
                print ("Error: " .. message)
            end
        end
    end
    functionLock = false
end

--
-- Argument parsing
--
function piepan._implArgument(key, value)
    assert(type(key) ~= nil, "key cannot be nil")

    value = value or ""
    if piepan.args[key] == nil then
        piepan.args[key] = {value}
    else
        table.insert(piepan.args[key], value)
    end
end

--
-- piepan.meta
--
function piepan.meta.__index(table, key)
    return piepan[key]
end

--
{'fraction_non_alphanumeric': 0.10634441087613293, 'fraction_numerical': 0.0006042296072507553, 'mean_word_length': 2.2266081871345027, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 9, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2589852', 'n_tokens_mistral': 2000, 'n_tokens_neox': 1975, 'n_words': 552}