<commit_before>import discord
import os
import json
import subprocess
import hastebin
from datetime import datetime

def look_for_code(msg):
    """Checks the discord message for a code block. If there's no code, it returns an empty string."""

    try:
        code = msg.split("```")[1] # Looks for anything wrapped in a ``` block
        while code[0] == "`": # Gets rid of any extra `
            code = code[1:]
        return code.split("\n")
    except IndexError: # There's no ``` in the message content
        return ""

def detect_language(msg, code):
    """Checks code language and gives the following functions information regarding how to run the code."""

    lang_dict = {}
    for language in os.listdir(os.path.dirname(os.path.realpath(__file__)) + "/languages"):
        if language != "README.md": # That's not a .json file!
            with open(os.path.dirname(os.path.realpath(__file__)) + "/languages/" + language) as langjson:
                lang_dict[language[:-5]] = json.load(langjson)

    # Check markdown
    for language in lang_dict.keys():
        if code[0].lower() in lang_dict[language]["known_naming"]:
            code[0] = "" # Erase markdown language
            markdown_language = language

    # Check argument
    try:
        argument_provided = msg.split("```")[0].split(" ")[1].strip()
        for language in lang_dict.keys():
            if argument_provided.lower() in lang_dict[language]["known_naming"]:
                return lang_dict[language], code
    except IndexError:
        pass

    try:
        return lang_dict[markdown_language], code
    except UnboundLocalError: # There's no valid markdown
        return "", code

def create_file(language, extension, code, compiled):
    """create a file with the code provided, so it can be run or compiled later."""

    if not os.path.isdir(os.path.dirname(os.path.realpath(__file__)) + "/code"): # Generates /code folder if it doesn't exist
        os.mkdir(os.path.dirname(os.path.realpath(__file__)) + "/code")

    if not os.path.isdir(os.path.dirname(os.path.realpath(__file__)) + "/code/" + language): # Generates /code/language folder if it doesn't exist
        os.mkdir(os.path.dirname(os.path.realpath(__file__)) + "/code/" + language)

    file_path = "%s/code/%s/%s%s" % (os.path.dirname(os.path.realpath(__file__)), language, datetime.now().strftime("%d-%m-%Y_%H:%M:%S.%f"),  extension)
    with open(file_path, "a") as file: # Open the file to write on
        for line in code:
            file.write("%s\n" % line)

    if compiled: # Creates a special character free copy for compiling if it's needed
        file_compiled = "%s/code/%s/exec" % (os.path.dirname(os.path.realpath(__file__)), language)
        if not os.path.exists(file_compiled):
            os.mkdir(file_compiled)

        try:
            os.remove(file_compiled + "/plaincode" + extension)
        except FileNotFoundError:
            pass
        with open(file_compiled + "/plaincode" + extension, "a") as file: # Open the file to write on
            for line in code:
                file.write("%s\n" % line)
    else:
        file_compiled = ""

    return file_path, file_compiled

def run_compiler(file_path, language, compiler_exec, extension, flags = ""):
    """runs the compiler and generates an executable."""

    run_process = subprocess.Popen(["umlbox", "--cwd", "/arcoex", "-B", "-fw", "/arcoex", "-fw", "/bot/code", "-f", "/", "-m", "512M", "-T", "65", compiler_exec] + flags + [file_path + "/executable", file_path + "/plaincode" + extension], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
    try:
        stdout, stderr = run_process.communicate(timeout=60)
        if stdout:
            return "", stdout.decode("utf-8")
        elif stderr:
            return "", stderr.decode("utf-8")
        else:
            return file_path + "/executable", ""
    except subprocess.TimeoutExpired:
        run_process.kill()
        return 0

def execute_code(file_path, run_command, flags):
    """Creates a subprocess that runs the file, then grabs the stdout and stderr of said process."""

    timeout_flag = False
    if run_command: # For non-compiled languages
        run_process = subprocess.Popen(["umlbox", "--cwd", "/arcoex", "-B", "-fw", "/arcoex", "-f", "/bot/code", "-m", "512M", "-T", "10", "env", "LANG=en_US.UTF-8", run_command] + flags + [file_path], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    else:
        run_process = subprocess.Popen(["umlbox", "--cwd", "/arcoex", "-B", "-fw", "/arcoex", "-f", "/bot/code", "-m", "512M", "-T", "10", "env", "LANG=en_US.UTF-8", file_path], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    try:
        stdout, stderr = run_process.communicate(timeout=8)
    except subprocess.TimeoutExpired:
        stdout, stderr, timeout_flag = timeout(run_process)

    return stdout.decode("utf-8"), stderr.decode("utf-8"), timeout_flag

def timeout(process):
    """If the process timed out, returns the last 5 lines of output and kills the process"""
    line_number = 0
    stderr = b""
    stdout = b""
    while line_number <= 5:
        stdout += process.stdout.readline()
        line_number += 1
    process.kill()
    timeout_flag = True
    return stdout, stderr, timeout_flag

async def send_instructions(msg, client):
    """Sends the user who mentioned the bot all the instructions of how to use it."""

    supported_languages_raw = os.listdir(os.path.dirname(os.path.realpath(__file__)) + "/languages")
    supported_languages = []
    for language_raw in supported_languages_raw:
        if language_raw == "README.md":
            pass
        else:
            supported_languages.append(language_raw[:-5])

    instructions = ("Arcoex stands for **ar**bitrary **co**de **ex**ecution, and that's what this bot does! There are two ways to use me (you can use both at the same time if you want to):"
    "\n\n**1.** Mention me among with the language of the code you want to run, and then add the code warped in between \`\`\`, making a code block. (This method overrides the next one if"
    "both are specified at the same time) Here's an example:\n\n<@" + client.user.id + "> bash ```\n echo(\"I'm using the first method!\")```\n**2.** Mention me among your code warped in between"
    "\`\`\`, and specify the language of your code right after the first set of \`\`\` (This method will add syntax markdown to your code). Here's an example:\n\n<@350327901788569612> ```bash"
    "\n echo(\"I'm using the second method!\")```\nSo far, the supported languages are " + ", ".join(supported_languages[:-1]) + " and " + supported_languages[-1] + "."
    "\n\nMessage Kurolox if you want to add more, or check out the Github page if you want to contribute: https://github.com/Kurolox/ArcoexBot")

    await client.send_message(msg.author, instructions)
    await client.send_message(msg.channel, "I've sent you the bot instructions via PM.")

async def bot_reply(msg, client, signal, code_output="", compiler_output="", language=""):
    """Makes the bot reply depending on the signal."""

    try:
        if signal == 0: # There was no code detected on the message
            await client.send_message(msg.channel, "I'm sorry, but I'm not seeing any code to run.")
        elif signal == 1: # There was only a mention of the bot
            await send_instructions(msg, client)
        elif signal == 2: # detect_language() couldn't detect the language
            await client.send_message(msg.channel, "I'm sorry, but you didn't specify the language of the code or it isn't supported yet.")
        elif signal == 3: # The compiler ran into issues
            await client.send_message(msg.channel, "I've encountered the following error when compiling your %s code. \n```\n%s```" % (language, compiler_output))
        elif signal == 4: # The process timeouted
            await client.send_message(msg.channel, "I'm sorry, but your request took too long. Here are the last 5 lines from the output.\n```\n%s```" % code_output)
        elif signal == 5: # There were errors when running the code
            await client.send_message(msg.channel, "I've encountered the following error when running your %s code. \n```\n%s```" % (language, code_output))
        elif signal == 6: # Everything went well
            await client.send_message(msg.channel, "Here's the output of your %s code. \n```\n%s```" % (language, code_output))
    except discord.errors.HTTPException: # Unless the message was +2000 characters
        try:
            await client.send_message(msg.channel, "I'm sorry, but the output is too long for Discord. You can check the output of your %s code here. %s" % (language, hastebin.post(code_output)))
        except KeyError: # Not even hastebin wants the output
            await client.send_message(msg.channel, "I'm sorry, but the output is too long for Discord. Hell, it's even too long for hastebin. Though luck, I guess. *¯\_(ツ)_/¯*")
async def code(msg, client):
    """Grab the code block from a message, run it and return the output."""

    code = look_for_code(msg.content)
    if not code:
        if msg.content != ("<@%s>" % client.user.id): # if the message content is not just a mention
            await bot_reply(msg, client, 0)
        else: # if the message content is only a mention to the bot
            await bot_reply(msg, client, 1)
    else:
        lang_json, code = detect_language(msg.content, code)
        if not lang_json: # The language wasn't detected
            await bot_reply(msg, client, 2)
        else:
            file_path, compiled_copy = create_file(lang_json["language"], lang_json["file_extension"], code, lang_json["compiled"])
            if lang_json["compiled"]: # Code needs to be compiled
                exec_path, compiler_output = run_compiler(compiled_copy, lang_json["language"], lang_json["compiler_exec"],lang_json["file_extension"], flags= lang_json["compiler_flags"])
                if compiler_output: # Errors when compiling
                    await bot_reply(msg, client, 3, compiler_output=compiler_output, language=lang_json["language"])
                else:
                    output, error, timeout_flag = execute_code(exec_path, lang_json["exec"], lang_json["exec_flags"])
                    if timeout_flag: # The process did timeout
                        await bot_reply(msg, client, 4, code_output=output)
                    elif error: # There's something on stderr
                        await bot_reply(msg, client, 5, code_output=error, language=lang_json["language"])
                    else: # Everything went fine
                        await bot_reply(msg, client, 6, code_output=output, language=lang_json["language"])

            else: # Code can be run directly
                output, error, timeout_flag = execute_code(file_path, lang_json["exec"], lang_json["exec_flags"])
                if timeout_flag: # The process did timeout
                    await bot_reply(msg, client, 4, code_output=output)
                elif error: # There's something on stderr
                    await bot_reply(msg, client, 5, code_output=error, language=lang_json["language"])
                else: # Everything went fine
                    await bot_reply(msg, client, 6, code_output=output, language=lang_json["language"])
<commit_msg>Removed a testing leftover.<commit_after>import discord
import os
import json
import subprocess
import hastebin
from datetime import datetime

def look_for_code(msg):
    """Checks the discord message for a code block. If there's no code, it returns an empty string."""

    try:
        code = msg.split("```")[1] # Looks for anything wrapped in a ``` block
        while code[0] == "`": # Gets rid of any extra `
            code = code[1:]
        return code.split("\n")
    except IndexError: # There's no ``` in the message content
        return ""

def detect_language(msg, code):
    """Checks code language and gives the following functions information regarding how to run the code."""

    lang_dict = {}
    for language in os.listdir(os.path.dirname(os.path.realpath(__file__)) + "/languages"):
        if language != "README.md": # That's not a .json file!
            with open(os.path.dirname(os.path.realpath(__file__)) + "/languages/" + language) as langjson:
                lang_dict[language[:-5]] = json.load(langjson)

    # Check markdown
    for language in lang_dict.keys():
        if code[0].lower() in lang_dict[language]["known_naming"]:
            code[0] = "" # Erase markdown language
            markdown_language = language

    # Check argument
    try:
        argument_provided = msg.split("```")[0].split(" ")[1].strip()
        for language in lang_dict.keys():
            if argument_provided.lower() in lang_dict[language]["known_naming"]:
                return lang_dict[language], code
    except IndexError:
        pass

    try:
        return lang_dict[markdown_language], code
    except UnboundLocalError: # There's no valid markdown
        return "", code

def create_file(language, extension, code, compiled):
    """create a file with the code provided, so it can be run or compiled later."""

    if not os.path.isdir(os.path.dirname(os.path.realpath(__file__)) + "/code"): # Generates /code folder if it doesn't exist
        os.mkdir(os.path.dirname(os.path.realpath(__file__)) + "/code")

    if not os.path.isdir(os.path.dirname(os.path.realpath(__file__)) + "/code/" + language): # Generates /code/language folder if it doesn't exist
        os.mkdir(os.path.dirname(os.path.realpath(__file__)) + "/code/" + language)

    file_path = "%s/code/%s/%s%s" % (os.path.dirname(os.path.realpath(__file__)), language, datetime.now().strftime("%d-%m-%Y_%H:%M:%S.%f"),  extension)
    with open(file_path, "a") as file: # Open the file to write on
        for line in code:
            file.write("%s\n" % line)

    if compiled: # Creates a special character free copy for compiling if it's needed
        file_compiled = "%s/code/%s/exec" % (os.path.dirname(os.path.realpath(__file__)), language)
        if not os.path.exists(file_compiled):
            os.mkdir(file_compiled)

        try:
            os.remove(file_compiled + "/plaincode" + extension)
        except FileNotFoundError:
            pass
        with open(file_compiled + "/plaincode" + extension, "a") as file: # Open the file to write on
            for line in code:
                file.write("%s\n" % line)
    else:
        file_compiled = ""

    return file_path, file_compiled

def run_compiler(file_path, language, compiler_exec, extension, flags = ""):
    """runs the compiler and generates an executable."""

    run_process = subprocess.Popen(["umlbox", "--cwd", "/arcoex", "-B", "-fw", "/arcoex", "-fw", "/bot/code", "-m", "512M", "-T", "65", compiler_exec] + flags + [file_path + "/executable", file_path + "/plaincode" + extension], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
    try:
        stdout, stderr = run_process.communicate(timeout=60)
        if stdout:
            return "", stdout.decode("utf-8")
        elif stderr:
            return "", stderr.decode("utf-8")
        else:
            return file_path + "/executable", ""
    except subprocess.TimeoutExpired:
        run_process.kill()
        return 0

def execute_code(file_path, run_command, flags):
    """Creates a subprocess that runs the file, then grabs the stdout and stderr of said process."""

    timeout_flag = False
    if run_command: # For non-compiled languages
        run_process = subprocess.Popen(["umlbox", "--cwd", "/arcoex", "-B", "-fw", "/arcoex", "-f", "/bot/code", "-m", "512M", "-T", "10", "env", "LANG=en_US.UTF-8", run_command] + flags + [file_path], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    else:
        run_process = subprocess.Popen(["umlbox", "--cwd", "/arcoex", "-B", "-fw", "/arcoex", "-f", "/bot/code", "-m", "512M", "-T", "10", "env", "LANG=en_US.UTF-8", file_path], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    try:
        stdout, stderr = run_process.communicate(timeout=8)
    except subprocess.TimeoutExpired:
        stdout, stderr, timeout_flag = timeout(run_process)

    return stdout.decode("utf-8"), stderr.decode("utf-8"), timeout_flag

def timeout(process):
    """If the process timed out, returns the last 5 lines of output and kills the process"""
    line_number = 0
    stderr = b""
    stdout = b""
    while line_number <= 5:
        stdout += process.stdout.readline()
        line_number += 1
    process.kill()
    timeout_flag = True
    return stdout, stderr, timeout_flag

async def send_instructions(msg, client):
    """Sends the user who mentioned the bot all the instructions of how to use it."""

    supported_languages_raw = os.listdir(os.path.dirname(os.path.realpath(__file__)) + "/languages")
    supported_languages = []
    for language_raw in supported_languages_raw:
        if language_raw == "README.md":
            pass
        else:
            supported_languages.append(language_raw[:-5])

    instructions = ("Arcoex stands for **ar**bitrary **co**de **ex**ecution, and that's what this bot does! There are two ways to use me (you can use both at the same time if you want to):"
    "\n\n**1.** Mention me among with the language of the code you want to run, and then add the code warped in between \`\`\`, making a code block. (This method overrides the next one if"
    "both are specified at the same time) Here's an example:\n\n<@" + client.user.id + "> bash ```\n echo(\"I'm using the first method!\")```\n**2.** Mention me among your code warped in between"
    "\`\`\`, and specify the language of your code right after the first set of \`\`\` (This method will add syntax markdown to your code). Here's an example:\n\n<@350327901788569612> ```bash"
    "\n echo(\"I'm using the second method!\")```\nSo far, the supported languages are " + ", ".join(supported_languages[:-1]) + " and " + supported_languages[-1] + "."
    "\n\nMessage Kurolox if you want to add more, or check out the Github page if you want to contribute: https://github.com/Kurolox/ArcoexBot")

    await client.send_message(msg.author, instructions)
    await client.send_message(msg.channel, "I've sent you the bot instructions via PM.")

async def bot_reply(msg, client, signal, code_output="", compiler_output="", language=""):
    """Makes the bot reply depending on the signal."""

    try:
        if signal == 0: # There was no code detected on the message
            await client.send_message(msg.channel, "I'm sorry, but I'm not seeing any code to run.")
        elif signal == 1: # There was only a mention of the bot
            await send_instructions(msg, client)
        elif signal == 2: # detect_language() couldn't detect the language
            await client.send_message(msg.channel, "I'm sorry, but you didn't specify the language of the code or it isn't supported yet.")
        elif signal == 3: # The compiler ran into issues
            await client.send_message(msg.channel, "I've encountered the following error when compiling your %s code. \n```\n%s```" % (language, compiler_output))
        elif signal == 4: # The process timeouted
            await client.send_message(msg.channel, "I'm sorry, but your request took too long. Here are the last 5 lines from the output.\n```\n%s```" % code_output)
        elif signal == 5: # There were errors when running the code
            await client.send_message(msg.channel, "I've encountered the following error when running your %s code. \n```\n%s```" % (language, code_output))
        elif signal == 6: # Everything went well
            await client.send_message(msg.channel, "Here's the output of your %s code. \n```\n%s```" % (language, code_output))
    except discord.errors.HTTPException: # Unless the message was +2000 characters
        try:
            await client.send_message(msg.channel, "I'm sorry, but the output is too long for Discord. You can check the output of your %s code here. %s" % (language, hastebin.post(code_output)))
        except KeyError: # Not even hastebin wants the output
            await client.send_message(msg.channel, "I'm sorry, but the output is too long for Discord. Hell, it's even too long for hastebin. Though luck, I guess. *¯\_(ツ)_/¯*")
async def code(msg, client):
    """Grab the code block from a message, run it and return the output."""

    code = look_for_code(msg.content)
    if not code:
        if msg.content != ("<@%s>" % client.user.id): # if the message content is not just a mention
            await bot_reply(msg, client, 0)
        else: # if the message content is only a mention to the bot
            await bot_reply(msg, client, 1)
    else:
        lang_json, code = detect_language(msg.content, code)
        if not lang_json: # The language wasn't detected
            await bot_reply(msg, client, 2)
        else:
            file_path, compiled_copy = create_file(lang_json["language"], lang_json["file_extension"], code, lang_json["compiled"])
            if lang_json["compiled"]: # Code needs to be compiled
                exec_path, compiler_output = run_compiler(compiled_copy, lang_json["language"], lang_json["compiler_exec"],lang_json["file_extension"], flags= lang_json["compiler_flags"])
                if compiler_output: # Errors when compiling
                    await bot_reply(msg, client, 3, compiler_output=compiler_output, language=lang_json["language"])
                else:
                    output, error, timeout_flag = execute_code(exec_path, lang_json["exec"], lang_json["exec_flags"])
                    if timeout_flag: # The process did timeout
                        await bot_reply(msg, client, 4, code_output=output)
                    elif error: # There's something on stderr
                        await bot_reply(msg, client, 5, code_output=error, language=lang_json["language"])
                    else: # Everything went fine
                        await bot_reply(msg, client, 6, code_output=output, language=lang_json["language"])

            else: # Code can be run directly
                output, error, timeout_flag = execute_code(file_path, lang_json["exec"], lang_json["exec_flags"])
                if timeout_flag: # The process did timeout
                    await bot_reply(msg, client, 4, code_output=output)
                elif error: # There's something on stderr
                    await bot_reply(msg, client, 5, code_output=error, language=lang_json["language"])
                else: # Everything went fine
                    await bot_reply(msg, client, 6, code_output=output, language=lang_json["language"])
<|endoftext|>


<commit_before>import discord
import os
import json
import subprocess
from datetime import datetime

greetings = "Arcoex stands for **ar**bitrary **co**de **ex**ecution, and that's what this bot does! There are two ways to use me (you can use both at the same time if you want to):\n\n**1.** Mention me among with the language of the code you want to run, and then add the code warped in between \`\`\`, making a code block. (This method overrides the next one if both are specified at the same time) Here's an example:\n\n<@350327901788569612> bash ```\n echo(\"I'm using the first method!\")```\n**2.** Mention me among your code warped in between \`\`\`, and specify the language of your code right after the first set of \`\`\` (This method will add syntax markdown to your code). Here's an example:\n\n<@350327901788569612> ```bash\n echo(\"I'm using the second method!\")```\nSo far, the supported languages are bash, rust, cpp, javascript, guile and python. Message Kurolox if you want to add more!"

def look_for_code(msg):
    """Checks the discord message for a code block. If there's no code, it returns an empty string."""

    try:
        code = msg.split("```")[1] # Looks for anything wrapped in a ``` block
        return code.split("\n")
    except IndexError: # There's no ``` in the message content
        return ""

def detect_language(msg, code):
    """Checks code language and gives the following functions information regarding how to run the code."""

    lang_dict = {}
    for language in os.listdir(os.path.dirname(os.path.realpath(__file__)) + "/languages"):
        with open(os.path.dirname(os.path.realpath(__file__)) + "/languages/" + language) as langjson:
            lang_dict[language[:-5]] = json.load(langjson)

    # Check markdown
    for language in lang_dict.keys():
        if code[0] in lang_dict[language]["known_naming"]:
            code[0] = "" # Erase markdown language
            markdown_language = language

    # Check argument
    try:
        argument_provided = msg.split("```")[0].split(" ")[1]
        for language in lang_dict.keys():
            if argument_provided in lang_dict[language]["known_naming"]:
                return lang_dict[argument_provided], code
    except IndexError:
       pass

    try:
        return lang_dict[markdown_language], code
    except UnboundLocalError: # There's no valid markdown
        return "", code

def create_file(language, extension, code, compiled):
    """create a file with the code provided, so it can be run or compiled later."""

    if not os.path.isdir(os.path.dirname(os.path.realpath(__file__)) + "/code"): # Generates /code folder if it doesn't exist
        os.mkdir(os.path.dirname(os.path.realpath(__file__)) + "/code")

    if not os.path.isdir(os.path.dirname(os.path.realpath(__file__)) + "/code/" + language): # Generates /code/language folder if it doesn't exist
        os.mkdir(os.path.dirname(os.path.realpath(__file__)) + "/code/" + language)

    file_path = "%s/code/%s/%s%s" % (os.path.dirname(os.path.realpath(__file__)), language, datetime.now().strftime("%d-%m-%Y_%H:%M:%S.%f"),  extension)
    with open(file_path, "a") as file: # Open the file to write on
        for line in code:
            file.write("%s\n" % line)

    if compiled: # Creates a special character free copy for compiling if it's needed
        file_compiled = "%s/code/%s/exec" % (os.path.dirname(os.path.realpath(__file__)), language)
        if not os.path.exists(file_compiled):
            os.mkdir(file_compiled)

        try:
            os.remove(file_compiled + "/plaincode" + extension)
        except FileNotFoundError:
            pass
        with open(file_compiled + "/plaincode" + extension, "a") as file: # Open the file to write on
            for line in code:
                file.write("%s\n" % line)
    else:
        file_compiled = ""

    return file_path, file_compiled

def run_compiler(file_path, language, compiler_exec, extension, flags = ""):
    """runs the compiler and generates an executable."""

    run_process = subprocess.Popen(["umlbox", "--cwd", "/arcoex", "-B", "-fw", "/arcoex", "-fw", "/bot/code", "-m", "512M", "-T", "65", compiler_exec, flags, file_path + "/executable", file_path + "/plaincode" + extension], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
    try:
        stdout, stderr = run_process.communicate(timeout=60)
        if stdout:
            return "", stdout.decode("utf-8")
        elif stderr:
            return "", stderr.decode("utf-8")
        else:
            return file_path + "/executable", ""
    except subprocess.TimeoutExpired:
        run_process.kill()
        return 0

def execute_code(file_path, run_command):
    """Creates a subprocess that runs the file, then grabs the stdout and stderr of said process."""

    timeout_flag = False
    if run_command: # For non-compiled languages
        run_process = subprocess.Popen(["umlbox", "--cwd", "/arcoex", "-B", "-fw", "/arcoex", "-f", "/bot/code", "-m", "512M", "-T", "10", run_command, file_path], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    else:
        run_process = subprocess.Popen(["umlbox", "--cwd", "/arcoex", "-B", "-fw", "/arcoex", "-f", "/bot/code", "-m", "512M", "-T", "10", file_path], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    try:
        stdout, stderr = run_process.communicate(timeout=5)
    except subprocess.TimeoutExpired:
        stdout, stderr, timeout_flag = timeout(run_process)

    return stdout.decode("utf-8"), stderr.decode("utf-8"), timeout_flag

def timeout(process):
    """If the process timed out, returns the last 5 lines of output and kills the process"""
    line_number = 0
    stderr = b""
    stdout = b""
    while line_number < 5:
        stdout += process.stdout.readline()
        line_number += 1
    process.kill()
    timeout_flag = True
    return stdout, stderr, timeout_flag

async def bot_reply(msg, client, signal, code_output="", compiler_output="", language=""):
    """Makes the bot reply depending on the signal."""

    if signal == 0: # There was no code detected on the message
        await client.send_message(msg.channel, "I'm sorry, but I'm not seeing any code to run.")
    elif signal == 1: # There was only a mention of the bot
        await client.send_message(msg.channel, greetings)
    elif signal == 2: # detect_language() couldn't detect the language
        await client.send_message(msg.channel, "I'm sorry, but you didn't specify the language of the code or it isn't supported yet.")
    elif signal == 3: # The compiler ran into issues
        await client.send_message(msg.channel, "I've encountered the following error when compiling your %s code. \n```\n%s```" % (language, compiler_output))
    elif signal == 4: # The process timeouted
        await client.send_message(msg.channel, "I'm sorry, but your request took too long. Here are the last 5 lines from the output.\n```\n%s```" % code_output)
    elif signal == 5: # There were errors when running the code
        await client.send_message(msg.channel, "I've encountered the following error when running your %s code. \n```\n%s```" % (language, code_output))
    elif signal == 6: # Everything went well
        await client.send_message(msg.channel, "Here's the output of your %s code. \n```\n%s```" % (language, code_output))

async def code(msg, client):
    """Grab the code block from a message, run it and return the output."""

    code = look_for_code(msg.content)
    if not code:
        if msg.content != ("<@%s>" % client.user.id): # if the message content is not just a mention
            await bot_reply(msg, client, 0)
        else: # if the message content is only a mention to the bot
            await bot_reply(msg, client, 1)
    else:
        lang_json, code = detect_language(msg.content, code)
        if not lang_json: # The language wasn't detected
            await bot_reply(msg, client, 2)
        else:
            file_path, compiled_copy = create_file(lang_json["language"], lang_json["file_extension"], code, lang_json["compiled"])
            if lang_json["compiled"]: # Code needs to be compiled
                exec_path, compiler_output = run_compiler(compiled_copy, lang_json["language"], lang_json["compiler_exec"],lang_json["file_extension"], flags= lang_json["compiler_flags"])
                if compiler_output: # Errors when compiling
                    await bot_reply(msg, client, 3, compiler_output=compiler_output, language=lang_json["language"])
                else:
                    output, error, timeout_flag = execute_code(exec_path, "")
                    if timeout_flag: # The process did timeout
                        await bot_reply(msg, client, 4, code_output=output)
                    elif error: # There's something on stderr
                        await bot_reply(msg, client, 5, code_output=error, language=lang_json["language"])
                    else: # Everything went fine
                        await bot_reply(msg, client, 6, code_output=output, language=lang_json["language"])

            else: # Code can be run directly
                output, error, timeout_flag = execute_code(file_path, lang_json["run_command"])
                if timeout_flag: # The process did timeout
                    await bot_reply(msg, client, 4, code_output=output)
                elif error: # There's something on stderr
                    await bot_reply(msg, client, 5, code_output=error, language=lang_json["language"])
                else: # Everything went fine
                    await bot_reply(msg, client, 6, code_output=output, language=lang_json["language"])
<commit_msg>Fixed caps not working when detecting languages<commit_after>import discord
import os
import json
import subprocess
from datetime import datetime

greetings = "Arcoex stands for **ar**bitrary **co**de **ex**ecution, and that's what this bot does! There are two ways to use me (you can use both at the same time if you want to):\n\n**1.** Mention me among with the language of the code you want to run, and then add the code warped in between \`\`\`, making a code block. (This method overrides the next one if both are specified at the same time) Here's an example:\n\n<@350327901788569612> bash ```\n echo(\"I'm using the first method!\")```\n**2.** Mention me among your code warped in between \`\`\`, and specify the language of your code right after the first set of \`\`\` (This method will add syntax markdown to your code). Here's an example:\n\n<@350327901788569612> ```bash\n echo(\"I'm using the second method!\")```\nSo far, the supported languages are bash, rust, cpp, javascript, guile and python. Message Kurolox if you want to add more!"

def look_for_code(msg):
    """Checks the discord message for a code block. If there's no code, it returns an empty string."""

    try:
        code = msg.split("```")[1] # Looks for anything wrapped in a ``` block
        return code.split("\n")
    except IndexError: # There's no ``` in the message content
        return ""

def detect_language(msg, code):
    """Checks code language and gives the following functions information regarding how to run the code."""

    lang_dict = {}
    for language in os.listdir(os.path.dirname(os.path.realpath(__file__)) + "/languages"):
        with open(os.path.dirname(os.path.realpath(__file__)) + "/languages/" + language) as langjson:
            lang_dict[language[:-5]] = json.load(langjson)

    # Check markdown
    for language in lang_dict.keys():
        if code[0].lower() in lang_dict[language]["known_naming"]:
            code[0] = "" # Erase markdown language
            markdown_language = language

    # Check argument
    try:
        argument_provided = msg.split("```")[0].split(" ")[1]
        for language in lang_dict.keys():
            if argument_provided.lower() in lang_dict[language]["known_naming"]:
                return lang_dict[argument_provided], code
    except IndexError:
       pass

    try:
        return lang_dict[markdown_language], code
    except UnboundLocalError: # There's no valid markdown
        return "", code

def create_file(language, extension, code, compiled):
    """create a file with the code provided, so it can be run or compiled later."""

    if not os.path.isdir(os.path.dirname(os.path.realpath(__file__)) + "/code"): # Generates /code folder if it doesn't exist
        os.mkdir(os.path.dirname(os.path.realpath(__file__)) + "/code")

    if not os.path.isdir(os.path.dirname(os.path.realpath(__file__)) + "/code/" + language): # Generates /code/language folder if it doesn't exist
        os.mkdir(os.path.dirname(os.path.realpath(__file__)) + "/code/" + language)

    file_path = "%s/code/%s/%s%s" % (os.path.dirname(os.path.realpath(__file__)), language, datetime.now().strftime("%d-%m-%Y_%H:%M:%S.%f"),  extension)
    with open(file_path, "a") as file: # Open the file to write on
        for line in code:
            file.write("%s\n" % line)

    if compiled: # Creates a special character free copy for compiling if it's needed
        file_compiled = "%s/code/%s/exec" % (os.path.dirname(os.path.realpath(__file__)), language)
        if not os.path.exists(file_compiled):
            os.mkdir(file_compiled)

        try:
            os.remove(file_compiled + "/plaincode" + extension)
        except FileNotFoundError:
            pass
        with open(file_compiled + "/plaincode" + extension, "a") as file: # Open the file to write on
            for line in code:
                file.write("%s\n" % line)
    else:
        file_compiled = ""

    return file_path, file_compiled

def run_compiler(file_path, language, compiler_exec, extension, flags = ""):
    """runs the compiler and generates an executable."""

    run_process = subprocess.Popen(["umlbox", "--cwd", "/arcoex", "-B", "-fw", "/arcoex", "-fw", "/bot/code", "-m", "512M", "-T", "65", compiler_exec, flags, file_path + "/executable", file_path + "/plaincode" + extension], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
    try:
        stdout, stderr = run_process.communicate(timeout=60)
        if stdout:
            return "", stdout.decode("utf-8")
        elif stderr:
            return "", stderr.decode("utf-8")
        else:
            return file_path + "/executable", ""
    except subprocess.TimeoutExpired:
        run_process.kill()
        return 0

def execute_code(file_path, run_command):
    """Creates a subprocess that runs the file, then grabs the stdout and stderr of said process."""

    timeout_flag = False
    if run_command: # For non-compiled languages
        run_process = subprocess.Popen(["umlbox", "--cwd", "/arcoex", "-B", "-fw", "/arcoex", "-f", "/bot/code", "-m", "512M", "-T", "10", run_command, file_path], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    else:
        run_process = subprocess.Popen(["umlbox", "--cwd", "/arcoex", "-B", "-fw", "/arcoex", "-f", "/bot/code", "-m", "512M", "-T", "10", file_path], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    try:
        stdout, stderr = run_process.communicate(timeout=5)
    except subprocess.TimeoutExpired:
        stdout, stderr, timeout_flag = timeout(run_process)

    return stdout.decode("utf-8"), stderr.decode("utf-8"), timeout_flag

def timeout(process):
    """If the process timed out, returns the last 5 lines of output and kills the process"""
    line_number = 0
    stderr = b""
    stdout = b""
    while line_number < 5:
        stdout += process.stdout.readline()
        line_number += 1
    process.kill()
    timeout_flag = True
    return stdout, stderr, timeout_flag

async def bot_reply(msg, client, signal, code_output="", compiler_output="", language=""):
    """Makes the bot reply depending on the signal."""

    if signal == 0: # There was no code detected on the message
        await client.send_message(msg.channel, "I'm sorry, but I'm not seeing any code to run.")
    elif signal == 1: # There was only a mention of the bot
        await client.send_message(msg.channel, greetings)
    elif signal == 2: # detect_language() couldn't detect the language
        await client.send_message(msg.channel, "I'm sorry, but you didn't specify the language of the code or it isn't supported yet.")
    elif signal == 3: # The compiler ran into issues
        await client.send_message(msg.channel, "I've encountered the following error when compiling your %s code. \n```\n%s```" % (language, compiler_output))
    elif signal == 4: # The process timeouted
        await client.send_message(msg.channel, "I'm sorry, but your request took too long. Here are the last 5 lines from the output.\n```\n%s```" % code_output)
    elif signal == 5: # There were errors when running the code
        await client.send_message(msg.channel, "I've encountered the following error when running your %s code. \n```\n%s```" % (language, code_output))
    elif signal == 6: # Everything went well
        await client.send_message(msg.channel, "Here's the output of your %s code. \n```\n%s```" % (language, code_output))

async def code(msg, client):
    """Grab the code block from a message, run it and return the output."""

    code = look_for_code(msg.content)
    if not code:
        if msg.content != ("<@%s>" % client.user.id): # if the message content is not just a mention
            await bot_reply(msg, client, 0)
        else: # if the message content is only a mention to the bot
            await bot_reply(msg, client, 1)
    else:
        lang_json, code = detect_language(msg.content, code)
        if not lang_json: # The language wasn't detected
            await bot_reply(msg, client, 2)
        else:
            file_path, compiled_copy = create_file(lang_json["language"], lang_json["file_extension"], code, lang_json["compiled"])
            if lang_json["compiled"]: # Code needs to be compiled
                exec_path, compiler_output = run_compiler(compiled_copy, lang_json["language"], lang_json["compiler_exec"],lang_json["file_extension"], flags= lang_json["compiler_flags"])
                if compiler_output: # Errors when compiling
                    await bot_reply(msg, client, 3, compiler_output=compiler_output, language=lang_json["language"])
                else:
                    output, error, timeout_flag = execute_code(exec_path, "")
                    if timeout_flag: # The process did timeout
                        await bot_reply(msg, client, 4, code_output=output)
                    elif error: # There's something on stderr
                        await bot_reply(msg, client, 5, code_output=error, language=lang_json["language"])
                    else: # Everything went fine
                        await bot_reply(msg, client, 6, code_output=output, language=lang_json["language"])

            else: # Code can be run directly
                output, error, timeout_flag = execute_code(file_path, lang_json["run_command"])
                if timeout_flag: # The process did timeout
                    await bot_reply(msg, client, 4, code_output=output)
                elif error: # There's something on stderr
                    await bot_reply(msg, client, 5, code_output=error, language=lang_json["language"])
                else: # Everything went fine
                    await bot_reply(msg, client, 6, code_output=output, language=lang_json["language"])
<|endoftext|>


<commit_before>from __future__ import division
import os
import ast
import numpy as np

from pivy import coin
import FreeCAD as App

from openglider.jsonify import load, dumps, loads
from openglider.mesh import mesh_2d
from pivy_primitives_new_new import Line

importpath = os.path.join(os.path.dirname(__file__), '..', 'demokite.ods')

class OGBaseObject(object):
    def __init__(self, obj):
        obj.Proxy = self

    def execute(self, fp):
        pass

class OGBaseVP(object):
    def __init__(self, obj):
        obj.Proxy = self

    def attach(self, vobj):
        pass

    def updateData(self, fp, prop):
        pass

    def getDisplayModes(self, obj):
        mod = ["out"]
        return(mod)

    def __getstate__(self):
        return None

    def __setstate__(self, state):
        return None

class OGGlider(OGBaseObject):
    def __init__(self, obj):
        obj.addProperty("App::PropertyPythonObject",
                        "glider_instance", "object",
                        "glider_instance", 2)
        obj.addProperty("App::PropertyPythonObject",
                        "glider_2d", "object",
                        "parametric glider", 2)
        with open(os.path.dirname(__file__) + "/../glider2d.json", "r") as importfile:
            obj.glider_2d = load(importfile)["data"]
        obj.glider_instance = obj.glider_2d.get_glider_3d()
        obj.Proxy = self
        self.obj = obj
        super(OGGlider, self).__init__(obj)

    def __getstate__(self):
        out = {
            "glider_2d": dumps(self.obj.glider_2d),
            "name": self.obj.Name}
        return out

    def __setstate__(self, state):
        self.obj = App.ActiveDocument.getObject(state["name"])
        self.obj.addProperty("App::PropertyPythonObject",
                        "glider_instance", "object",
                        "glider_instance", 2)
        self.obj.addProperty("App::PropertyPythonObject",
                        "glider_2d", "object",
                        "parametric glider", 2)
        self.obj.glider_2d = loads(state["glider_2d"])["data"]
        self.obj.glider_instance = self.obj.glider_2d.get_glider_3d()
        return None

class OGGliderVP(OGBaseVP):
    def __init__(self, view_obj):
        view_obj.addProperty("App::PropertyInteger",
                             "num_ribs", "accuracy",
                             "num_ribs")
        view_obj.addProperty("App::PropertyInteger",
                             "profile_num", "accuracy",
                             "profile_num")
        view_obj.addProperty("App::PropertyInteger",
                             "line_num", "accuracy",
                             "line_num")
        view_obj.addProperty("App::PropertyBool",
                              "outside", "visual",
                              "outside")
        view_obj.num_ribs = 0
        view_obj.profile_num = 13
        view_obj.line_num = 5
        view_obj.outside = True
        super(OGGliderVP, self).__init__(view_obj)

    def attach(self, view_obj):
        self.vis_glider = coin.SoSeparator()
        self.vis_lines = coin.SoSeparator()
        self.material = coin.SoMaterial()
        self.seperator = coin.SoSeparator()
        self.view_obj = view_obj
        self.glider_instance = view_obj.Object.glider_instance
        self.material.diffuseColor = (.7, .7, .7)
        self.seperator.addChild(self.vis_glider)
        self.seperator.addChild(self.vis_lines)
        self.seperator.addChild(self.material)
        view_obj.addDisplayMode(self.seperator, 'out')

    def updateData(self, fp=None, prop=None):
        if hasattr(self, "view_obj"):
            if prop in ["num_ribs", "profile_num", "outside", None]:
                if hasattr(self.view_obj, "profile_num"):
                    numpoints = self.view_obj.profile_num
                    if numpoints < 5:
                        numpoints = 5
                    self.update_glider(midribs=self.view_obj.num_ribs,
                                       profile_numpoints=numpoints, outside=self.view_obj.outside)
            if prop in ["line_num", None]:
                if hasattr(self.view_obj, "line_num"):
                    self.update_lines(self.view_obj.line_num)

    def update_glider(self, midribs=0, profile_numpoints=20, outside=True):
        self.vis_glider.removeAllChildren()
        glider = self.glider_instance.copy_complete()
        glider.profile_numpoints = profile_numpoints
        if outside:
            if midribs == 0:
                vertexproperty = coin.SoVertexProperty()
                mesh = coin.SoQuadMesh()
                ribs = glider.ribs
                flat_coords = [i for rib in ribs for i in rib.profile_3d.data]
                vertexproperty.vertex.setValues(0, len(flat_coords), flat_coords)
                mesh.verticesPerRow = len(ribs[0].profile_3d.data)
                mesh.verticesPerColumn = len(ribs)
                mesh.vertexProperty = vertexproperty
                self.vis_glider.addChild(mesh)
                self.vis_glider.addChild(vertexproperty)
            else:
                for cell in glider.cells:
                    sep = coin.SoSeparator()
                    vertexproperty = coin.SoVertexProperty()
                    mesh = coin.SoQuadMesh()
                    ribs = [cell.midrib(pos / (midribs + 1))
                            for pos in range(midribs + 2)]
                    flat_coords = [i for rib in ribs for i in rib]
                    vertexproperty.vertex.setValues(0,
                                                    len(flat_coords),
                                                    flat_coords)
                    mesh.verticesPerRow = len(ribs[0])
                    mesh.verticesPerColumn = len(ribs)
                    mesh.vertexProperty = vertexproperty
                    sep.addChild(vertexproperty)
                    sep.addChild(mesh)
                    self.vis_glider.addChild(sep)
        else:  # show ribs
            for rib in glider.ribs:
                mesh = mesh_2d.from_rib(rib)
                if mesh.vertices is not None:
                    verts = list(mesh.vertices)
                    polygons = []
                    for i in mesh.polygons:
                        polygons += i
                        polygons.append(-1)

                    rib_sep = coin.SoSeparator()
                    self.vis_glider.addChild(rib_sep)
                    vertex_property = coin.SoVertexProperty()
                    face_set = coin.SoIndexedFaceSet()

                    shape_hint = coin.SoShapeHints()
                    shape_hint.vertexOrdering = coin.SoShapeHints.COUNTERCLOCKWISE

                    material = coin.SoMaterial()
                    material.diffuseColor = (.0, .0, .7)
                    rib_sep.addChild(material)

                    vertex_property.vertex.setValues(0, len(verts), verts)
                    face_set.coordIndex.setValues(0, len(polygons), list(polygons))
                    rib_sep.addChild(shape_hint)
                    rib_sep.addChild(vertex_property)
                    rib_sep.addChild(face_set)

            mesh = mesh_2d()
            for cell in glider.cells:
                for diagonal in cell.diagonals:
                    mesh += mesh_2d.from_diagonal(diagonal, cell)
                if mesh.vertices is not None:
                    verts = list(mesh.vertices)
                    polygons = []
                    for i in mesh.polygons:
                        polygons += i
                        polygons.append(-1)

                    diagonal_sep = coin.SoSeparator()
                    self.vis_glider.addChild(diagonal_sep)
                    vertex_property = coin.SoVertexProperty()
                    face_set = coin.SoIndexedFaceSet()

                    shape_hint = coin.SoShapeHints()
                    shape_hint.vertexOrdering = coin.SoShapeHints.COUNTERCLOCKWISE

                    material = coin.SoMaterial()
                    material.diffuseColor = (.7, .0, .0)
                    diagonal_sep.addChild(material)

                    vertex_property.vertex.setValues(0, len(verts), verts)
                    face_set.coordIndex.setValues(0, len(polygons), list(polygons))
                    diagonal_sep.addChild(shape_hint)
                    diagonal_sep.addChild(vertex_property)
                    diagonal_sep.addChild(face_set)

    def update_lines(self, num=3):
        self.vis_lines.removeAllChildren()
        for line in self.glider_instance.lineset.lines:
            points = line.get_line_points(numpoints=num)
            self.vis_lines.addChild(
                Line([[i[0], -i[1], i[2]] for i in points], dynamic=False))
            self.vis_lines.addChild(Line(points, dynamic=False))

    def onChanged(self, vp, prop):
        print("onChanged")
        self.updateData(vp, prop)

    def getIcon(self):
        return "new_glider.svg"

    def __getstate__(self):
        return None

    def __setstate__(self, state):
        self.updateData()
        return None
<commit_msg>errors<commit_after>from __future__ import division
import os
import ast
import numpy as np

from pivy import coin
import FreeCAD as App

from openglider.jsonify import load, dumps, loads
from openglider.mesh import mesh_2d
from pivy_primitives_new_new import Line

importpath = os.path.join(os.path.dirname(__file__), '..', 'demokite.ods')

class OGBaseObject(object):
    def __init__(self, obj):
        obj.Proxy = self

    def execute(self, fp):
        pass

class OGBaseVP(object):
    def __init__(self, obj):
        obj.Proxy = self

    def attach(self, vobj):
        pass

    def updateData(self, fp, prop):
        pass

    def getDisplayModes(self, obj):
        mod = ["out"]
        return(mod)

    def __getstate__(self):
        return None

    def __setstate__(self, state):
        return None

class OGGlider(OGBaseObject):
    def __init__(self, obj):
        obj.addProperty("App::PropertyPythonObject",
                        "glider_instance", "object",
                        "glider_instance", 2)
        obj.addProperty("App::PropertyPythonObject",
                        "glider_2d", "object",
                        "parametric glider", 2)
        with open(os.path.dirname(__file__) + "/../glider2d.json", "r") as importfile:
            obj.glider_2d = load(importfile)["data"]
        obj.glider_instance = obj.glider_2d.get_glider_3d()
        obj.Proxy = self
        self.obj = obj
        super(OGGlider, self).__init__(obj)

    def __getstate__(self):
        out = {
            "glider_2d": dumps(self.obj.glider_2d),
            "name": self.obj.Name}
        return out

    def __setstate__(self, state):
        self.obj = App.ActiveDocument.getObject(state["name"])
        self.obj.addProperty("App::PropertyPythonObject",
                        "glider_instance", "object",
                        "glider_instance", 2)
        self.obj.addProperty("App::PropertyPythonObject",
                        "glider_2d", "object",
                        "parametric glider", 2)
        self.obj.glider_2d = loads(state["glider_2d"])["data"]
        self.obj.glider_instance = self.obj.glider_2d.get_glider_3d()
        return None

class OGGliderVP(OGBaseVP):
    def __init__(self, view_obj):
        view_obj.addProperty("App::PropertyInteger",
                             "num_ribs", "accuracy",
                             "num_ribs")
        view_obj.addProperty("App::PropertyInteger",
                             "profile_num", "accuracy",
                             "profile_num")
        view_obj.addProperty("App::PropertyInteger",
                             "line_num", "accuracy",
                             "line_num")
        view_obj.addProperty("App::PropertyBool",
                              "outside", "visual",
                              "outside")
        view_obj.num_ribs = 0
        view_obj.profile_num = 13
        view_obj.line_num = 5
        view_obj.outside = True
        super(OGGliderVP, self).__init__(view_obj)

    def attach(self, view_obj):
        self.vis_glider = coin.SoSeparator()
        self.vis_lines = coin.SoSeparator()
        self.material = coin.SoMaterial()
        self.seperator = coin.SoSeparator()
        self.view_obj = view_obj
        self.glider_instance = view_obj.Object.glider_instance
        self.material.diffuseColor = (.7, .7, .7)
        self.seperator.addChild(self.vis_glider)
        self.seperator.addChild(self.vis_lines)
        self.seperator.addChild(self.material)
        view_obj.addDisplayMode(self.seperator, 'out')

    def updateData(self, fp=None, prop=None):
        if hasattr(self, "view_obj"):
            if prop in ["num_ribs", "profile_num", "outside", None]:
                if hasattr(self.view_obj, "profile_num"):
                    numpoints = self.view_obj.profile_num
                    if numpoints < 5:
                        numpoints = 5
                    self.update_glider(midribs=self.view_obj.num_ribs,
                                       profile_numpoints=numpoints, outside=self.view_obj.outside)
            if prop in ["line_num", None]:
                if hasattr(self.view_obj, "line_num"):
                    self.update_lines(self.view_obj.line_num)

    def update_glider(self, midribs=0, profile_numpoints=20, outside=True):
        self.vis_glider.removeAllChildren()
        glider = self.glider_instance.copy_complete()
        glider.profile_numpoints = profile_numpoints
        if outside:
            if midribs == 0:
                vertexproperty = coin.SoVertexProperty()
                mesh = coin.SoQuadMesh()
                ribs = glider.ribs
                flat_coords = [i for rib in ribs for i in rib.profile_3d.data]
                vertexproperty.vertex.setValues(0, len(flat_coords), flat_coords)
                mesh.verticesPerRow = len(ribs[0].profile_3d.data)
                mesh.verticesPerColumn = len(ribs)
                mesh.vertexProperty = vertexproperty
                self.vis_glider.addChild(mesh)
                self.vis_glider.addChild(vertexproperty)
            else:
                for cell in glider.cells:
                    sep = coin.SoSeparator()
                    vertexproperty = coin.SoVertexProperty()
                    mesh = coin.SoQuadMesh()
                    ribs = [cell.midrib(pos / (midribs + 1))
                            for pos in range(midribs + 2)]
                    flat_coords = [i for rib in ribs for i in rib]
                    vertexproperty.vertex.setValues(0,
                                                    len(flat_coords),
                                                    flat_coords)
                    mesh.verticesPerRow = len(ribs[0])
                    mesh.verticesPerColumn = len(ribs)
                    mesh.vertexProperty = vertexproperty
                    sep.addChild(vertexproperty)
                    sep.addChild(mesh)
                    self.vis_glider.addChild(sep)
        else:  # show ribs
            mesh = mesh_2d()
            for rib in glider.ribs:
                mesh += mesh_2d.from_rib(rib)
            if mesh.vertices is not None:
                verts = list(mesh.vertices)
                polygons = []
                for i in mesh.polygons:
                    polygons += i
                    polygons.append(-1)

                rib_sep = coin.SoSeparator()
                self.vis_glider.addChild(rib_sep)
                vertex_property = coin.SoVertexProperty()
                face_set = coin.SoIndexedFaceSet()

                shape_hint = coin.SoShapeHints()
                shape_hint.vertexOrdering = coin.SoShapeHints.COUNTERCLOCKWISE

                material = coin.SoMaterial()
                material.diffuseColor = (.0, .0, .7)
                rib_sep.addChild(material)

                vertex_property.vertex.setValues(0, len(verts), verts)
                face_set.coordIndex.setValues(0, len(polygons), list(polygons))
                rib_sep.addChild(shape_hint)
                rib_sep.addChild(vertex_property)
                rib_sep.addChild(face_set)

            mesh = mesh_2d()
            for cell in glider.cells:
                for diagonal in cell.diagonals:
                    mesh += mesh_2d.from_diagonal(diagonal, cell)
                if mesh.vertices is not None:
                    verts = list(mesh.vertices)
                    polygons = []
                    for i in mesh.polygons:
                        polygons += i
                        polygons.append(-1)

                    diagonal_sep = coin.SoSeparator()
                    self.vis_glider.addChild(diagonal_sep)
                    vertex_property = coin.SoVertexProperty()
                    face_set = coin.SoIndexedFaceSet()

                    shape_hint = coin.SoShapeHints()
                    shape_hint.vertexOrdering = coin.SoShapeHints.COUNTERCLOCKWISE

                    material = coin.SoMaterial()
                    material.diffuseColor = (.7, .0, .0)
                    diagonal_sep.addChild(material)

                    vertex_property.vertex.setValues(0, len(verts), verts)
                    face_set.coordIndex.setValues(0, len(polygons), list(polygons))
                    diagonal_sep.addChild(shape_hint)
                    diagonal_sep.addChild(vertex_property)
                    diagonal_sep.addChild(face_set)

    def update_lines(self, num=3):
        self.vis_lines.removeAllChildren()
        for line in self.glider_instance.lineset.lines:
            points = line.get_line_points(numpoints=num)
            self.vis_lines.addChild(
                Line([[i[0], -i[1], i[2]] for i in points], dynamic=False))
            self.vis_lines.addChild(Line(points, dynamic=False))

    def onChanged(self, vp, prop):
        print("onChanged")
        self.updateData(vp, prop)

    def getIcon(self):
        return "new_glider.svg"

    def __getstate__(self):
        return None

    def __setstate__(self, state):
        self.updateData()
        return None
<|endoftext|>


<commit_before>import zipfile
import StringIO
import json
import logging
import os
import shutil
import tempfile
import urlparse

from xml.etree import ElementTree as etree

from django.core.exceptions import ObjectDoesNotExist
from django.http import HttpResponse
from django.http import HttpResponseNotFound
from django.views.decorators.csrf import csrf_exempt
from django.views.decorators.http import require_http_methods

from openquake.commonlib import nrml
from openquake.engine import engine as oq_engine
from openquake.engine.db import models as oqe_models
from openquake.engine.export import hazard as hazard_export
from openquake.engine.export import risk as risk_export
from openquake.engine.utils.tasks import safely_call
from openquake.server import tasks, executor

METHOD_NOT_ALLOWED = 405
NOT_IMPLEMENTED = 501
JSON = 'application/json'

IGNORE_FIELDS = ('base_path', 'export_dir')
GEOM_FIELDS = ('region', 'region_constraint')
RISK_INPUTS = ('hazard_calculation', 'hazard_output')

DEFAULT_LOG_LEVEL = 'progress'

#: For exporting calculation outputs, the client can request a specific format
#: (xml, geojson, csv, etc.). If the client does not specify give them (NRML)
#: XML by default.
DEFAULT_EXPORT_TYPE = 'xml'

EXPORT_CONTENT_TYPE_MAP = dict(xml='application/xml',
                               geojson='application/json')
DEFAULT_CONTENT_TYPE = 'text/plain'

LOGGER = logging.getLogger('openquake.server')

ACCESS_HEADERS = {'Access-Control-Allow-Origin': '*',
                  'Access-Control-Allow-Methods': 'GET, POST, OPTIONS',
                  'Access-Control-Max-Age': 1000,
                  'Access-Control-Allow-Headers': '*'}

# Credit for this decorator to https://gist.github.com/aschem/1308865.
def cross_domain_ajax(func):
    def wrap(request, *args, **kwargs):
        # Firefox sends 'OPTIONS' request for cross-domain javascript call.
        if not request.method == "OPTIONS":
            response = func(request, *args, **kwargs)
        else:
            response = HttpResponse()
        for k, v in ACCESS_HEADERS.iteritems():
            response[k] = v
        return response
    return wrap

def _get_base_url(request):
    """
    Construct a base URL, given a request object.

    This comprises the protocol prefix (http:// or https://) and the host,
    which can include the port number. For example:
    http://www.openquake.org or https://www.openquake.org:8000.
    """
    if request.is_secure():
        base_url = 'https://%s'
    else:
        base_url = 'http://%s'
    base_url %= request.META['HTTP_HOST']
    return base_url

def _calc_to_response_data(calc):
    """
    Extract the calculation parameters into a dictionary.
    """
    fields = [x.name for x in calc._meta.fields if x.name not in IGNORE_FIELDS]
    response_data = {}
    for field_name in fields:
        try:
            value = getattr(calc, field_name)
            if value is not None:
                if field_name in GEOM_FIELDS:
                    response_data[field_name] = json.loads(value.geojson)
                elif field_name in RISK_INPUTS:
                    response_data[field_name] = value.id
                else:
                    response_data[field_name] = value
        except AttributeError:
            # Better that we miss an attribute than crash.
            pass
    return response_data

def create_detect_job_file(*candidates):
    def detect_job_file(files):
        for candidate in candidates:
            try:
                file_idx = [os.path.basename(f)
                            for f in files].index(candidate)
                return files[file_idx]
            except ValueError:
                pass
        raise RuntimeError("No job file found in %s for %s" % (
            str(files), str(candidates)))
    return detect_job_file

def _prepare_job(request, hazard_output_id, hazard_job_id,
                 detect_job_file):
    """
    Creates a temporary directory, move uploaded files there and
    select the job file by using the `detect_job_file` callable which
    accepts in input a list holding all the filenames ending with .ini

    :returns: job_file and temp_dir
    """
    temp_dir = tempfile.mkdtemp()
    files = []

    try:
        archive = zipfile.ZipFile(request.FILES['archive'])
    except KeyError:
        # move each file to a new temp dir, using the upload file names,
        # not the temporary ones
        for each_file in request.FILES.values():
            new_path = os.path.join(temp_dir, each_file.name)
            shutil.move(each_file.temporary_file_path(), new_path)
            files.append(new_path)
    else:  # extract the files from the archive into temp_dir
        archive.extractall(temp_dir)
        archive.close()
        for fname in os.listdir(temp_dir):
            files.append(os.path.join(temp_dir, fname))
    job_file = detect_job_file([f for f in files if f.endswith('.ini')])
    return job_file, temp_dir

def _is_source_model(tempfile):
    """
    Return true if an uploaded NRML file is a seismic source model.
    """
    tree = etree.iterparse(tempfile, events=('start', 'end'))
    # pop off the first elements, which should be a <nrml> element
    # and something else
    _, nrml_elem = tree.next()
    _, model_elem = tree.next()

    assert nrml_elem.tag == '{%s}nrml' % nrml.NAMESPACE, (
        "Input file is not a NRML artifact"
    )

    if model_elem.tag == '{%s}sourceModel' % nrml.NAMESPACE:
        return True
    return False

@require_http_methods(['GET'])
@cross_domain_ajax
def calc_info(request, job_type, calc_id):
    """
    Get a JSON blob containing all of parameters for the given calculation
    (specified by ``calc_id``). Also includes the current job status (
    executing, complete, etc.).
    """
    try:
        response_data = _get_calc_info(job_type, calc_id)
    except ObjectDoesNotExist:
        return HttpResponseNotFound()

    return HttpResponse(content=json.dumps(response_data), content_type=JSON)

# helper function to get job info and calculation params from the
# oq-engine DB, as a dictionary
def _get_calc_info(job_type, calc_id):
    if job_type == 'hazard':
        job = oqe_models.OqJob.objects.select_related().get(pk=calc_id)
        calc = job.get_oqparam()
    else:  # risk
        job = oqe_models.OqJob.objects.select_related()\
            .get(risk_calculation=calc_id)
        calc = job.risk_calculation

    response_data = _calc_to_response_data(calc)
    response_data['status'] = job.status
    return response_data

@require_http_methods(['GET'])
@cross_domain_ajax
def calc(request, job_type):
    """
    Get a list of calculations and report their id, status, description,
    and a url where more detailed information can be accessed.

    Responses are in JSON.
    """
    base_url = _get_base_url(request)

    calc_data = _get_calcs(job_type)
    if not calc_data:
        return HttpResponseNotFound()

    response_data = []
    for hc_id, status, desc in calc_data:
        url = urlparse.urljoin(base_url, 'v1/calc/%s/%d' % (job_type, hc_id))
        response_data.append(
            dict(id=hc_id, status=status, description=desc, url=url)
        )

    return HttpResponse(content=json.dumps(response_data),
                        content_type=JSON)

@csrf_exempt
@cross_domain_ajax
@require_http_methods(['POST'])
def run_calc(request, job_type):
    """
    Run a calculation.

    :param request:
        a `django.http.HttpRequest` object.
    :param job_type:
        string 'hazard' or 'risk'
    """
    callback_url = request.POST.get('callback_url')
    foreign_calc_id = request.POST.get('foreign_calculation_id')

    hazard_output_id = request.POST.get('hazard_output_id')
    hazard_job_id = request.POST.get('hazard_job_id')

    einfo, exctype = safely_call(
        _prepare_job, (request, hazard_output_id, hazard_job_id,
                       create_detect_job_file("job.ini", "job_risk.ini")))
    if exctype:
        tasks.update_calculation(callback_url, status="failed", einfo=einfo)
        raise exctype(einfo)
    else:
        job_file, temp_dir = einfo
    job, _fut = submit_job(job_file, temp_dir, request.POST['database'],
                           callback_url, foreign_calc_id,
                           hazard_output_id, hazard_job_id)
    try:
        response_data = _get_calc_info(job_type, job.calc_id)
    except ObjectDoesNotExist:
        return HttpResponseNotFound()

    return HttpResponse(content=json.dumps(response_data), content_type=JSON)

def submit_job(job_file, temp_dir, dbname,
               callback_url=None, foreign_calc_id=None,
               hazard_output_id=None, hazard_job_id=None,
               logfile=None):
    """
    Create a job object from the given job.ini file in the job directory
    and submit it to the job queue.
    """
    job, exctype = safely_call(
        oq_engine.job_from_file, (job_file, "platform", DEFAULT_LOG_LEVEL, [],
                                  hazard_output_id, hazard_job_id))
    if exctype:
        tasks.update_calculation(callback_url, status="failed", einfo=job)
        raise exctype(job)

    future = executor.submit(
        tasks.safely_call, tasks.run_calc, job.job_type, job.id, temp_dir,
        callback_url, foreign_calc_id, dbname, logfile)
    return job, future

def _get_calcs(job_type):
    """
    Helper function for get job+calculation data from the oq-engine database.

    Gets all calculation records available.
    """
    job_params = oqe_models.JobParam.objects.filter(
        name='description', job__risk_calculation__isnull=job_type == 'hazard',
        job__user_name='platform')
    if job_type == 'risk':
        return [(jp.job.risk_calculation, jp.job.status, jp.value)
                for jp in job_params]
    else:  # hazard
        return [(jp.job, jp.job.status, jp.value) for jp in job_params]

@require_http_methods(['GET'])
@cross_domain_ajax
def calc_results(request, job_type, calc_id):
    """
    Get a summarized list of calculation results for a given ``calc_id``.
    Result is a JSON array of objects containing the following attributes:

        * id
        * name
        * type (hazard_curve, hazard_map, etc.)
        * url (the exact url where the full result can be accessed)
    """
    # If the specified calculation doesn't exist OR is not yet complete,
    # throw back a 404.
    try:
        if job_type == 'risk':
            oqjob = oqe_models.RiskCalculation.objects.get(id=calc_id).oqjob
        else:
            oqjob = oqe_models.OqJob.objects.get(id=calc_id)
        if not oqjob.status == 'complete':
            return HttpResponseNotFound()
    except ObjectDoesNotExist:
        return HttpResponseNotFound()
    base_url = _get_base_url(request)

    results = oq_engine.get_outputs(job_type, calc_id)
    if not results:
        return HttpResponseNotFound()

    response_data = []
    for result in results:
        url = urlparse.urljoin(base_url,
                               'v1/calc/%s/result/%d' % (job_type, result.id))
        datum = dict(
            id=result.id,
            name=result.display_name,
            type=result.output_type,
            url=url,
        )
        response_data.append(datum)

    return HttpResponse(content=json.dumps(response_data))

@cross_domain_ajax
@require_http_methods(['GET'])
def get_result(request, job_type, result_id):
    """
    Download a specific result, by ``result_id``.

    Parameters for the GET request can include an `export_type`, such as 'xml',
    'geojson', 'csv', etc.
    """
    return _get_result(
        request, result_id,
        risk_export.export if job_type == 'risk' else hazard_export.export)

def _get_result(request, result_id, export_fn):
    """
    The common abstracted functionality for getting hazard or risk results.
    The functionality is the same, except for the hazard/risk specific
    ``export_fn``.

    :param request:
        `django.http.HttpRequest` object. Can contain a `export_type` GET
        param (the default is 'xml' if no param is specified).
    :param result_id:
        The id of the requested artifact.
    :param export_fn:
        Export function, which accepts the following params:

            * result_id (int)
            * target (a file path or file-like)
            * export_type (option kwarg)

    :returns:
        If the requested ``result_id`` is not available in the format
        designated by the `export_type`.

        Otherwise, return a `django.http.HttpResponse` containing the content
        of the requested artifact.
    """
    # If the result for the requested ID doesn't exist, OR
    # the job which it is related too is not complete,
    # throw back a 404.
    try:
        output = oqe_models.Output.objects.get(id=result_id)
        job = output.oq_job
        if not job.status == 'complete':
            return HttpResponseNotFound()
    except ObjectDoesNotExist:
        return HttpResponseNotFound()

    export_type = request.GET.get('export_type', DEFAULT_EXPORT_TYPE)

    content = StringIO.StringIO()
    try:
        content = export_fn(result_id, content, export_type=export_type)
    except NotImplementedError, err:
        # Throw back a 404 if the exact export parameters are not supported
        return HttpResponseNotFound(err.message)

    # Just in case the original StringIO object was closed:
    resp_content = StringIO.StringIO()
    # NOTE(LB): We assume that `content` was written to by using normal
    # file-like `write` calls; thus, the buflist should be populated with all
    # of the content. The exporter/writer might have closed the file object (if
    # so, we cannot read from it normally) so instead we should look at the
    # buflist.
    # NOTE(LB): This might be a really stupid implementation, but it's the best
    # I could come up with so far.
    resp_content.writelines(content.buflist)
    del content

    # TODO(LB): A possible necessary optimization--in the future--would be to
    # iteratively stream large files.
    # TODO(LB): Large files could pose a memory consumption problem.
    # TODO(LB): We also may want to limit the maximum file size of results sent
    # via http.
    resp_value = resp_content.getvalue()
    resp_content.close()
    # TODO: Need to look at `content_type`, otherwise XML gets treated at HTML
    # in the browser
    content_type = EXPORT_CONTENT_TYPE_MAP.get(export_type,
                                               DEFAULT_CONTENT_TYPE)
    return HttpResponse(resp_value, content_type=content_type)
<commit_msg>Fixed detect_job_file<commit_after>import zipfile
import StringIO
import json
import logging
import os
import shutil
import tempfile
import urlparse

from xml.etree import ElementTree as etree

from django.core.exceptions import ObjectDoesNotExist
from django.http import HttpResponse
from django.http import HttpResponseNotFound
from django.views.decorators.csrf import csrf_exempt
from django.views.decorators.http import require_http_methods

from openquake.commonlib import nrml
from openquake.engine import engine as oq_engine
from openquake.engine.db import models as oqe_models
from openquake.engine.export import hazard as hazard_export
from openquake.engine.export import risk as risk_export
from openquake.engine.utils.tasks import safely_call
from openquake.server import tasks, executor

METHOD_NOT_ALLOWED = 405
NOT_IMPLEMENTED = 501
JSON = 'application/json'

IGNORE_FIELDS = ('base_path', 'export_dir')
GEOM_FIELDS = ('region', 'region_constraint')
RISK_INPUTS = ('hazard_calculation', 'hazard_output')

DEFAULT_LOG_LEVEL = 'progress'

#: For exporting calculation outputs, the client can request a specific format
#: (xml, geojson, csv, etc.). If the client does not specify give them (NRML)
#: XML by default.
DEFAULT_EXPORT_TYPE = 'xml'

EXPORT_CONTENT_TYPE_MAP = dict(xml='application/xml',
                               geojson='application/json')
DEFAULT_CONTENT_TYPE = 'text/plain'

LOGGER = logging.getLogger('openquake.server')

ACCESS_HEADERS = {'Access-Control-Allow-Origin': '*',
                  'Access-Control-Allow-Methods': 'GET, POST, OPTIONS',
                  'Access-Control-Max-Age': 1000,
                  'Access-Control-Allow-Headers': '*'}

# Credit for this decorator to https://gist.github.com/aschem/1308865.
def cross_domain_ajax(func):
    def wrap(request, *args, **kwargs):
        # Firefox sends 'OPTIONS' request for cross-domain javascript call.
        if not request.method == "OPTIONS":
            response = func(request, *args, **kwargs)
        else:
            response = HttpResponse()
        for k, v in ACCESS_HEADERS.iteritems():
            response[k] = v
        return response
    return wrap

def _get_base_url(request):
    """
    Construct a base URL, given a request object.

    This comprises the protocol prefix (http:// or https://) and the host,
    which can include the port number. For example:
    http://www.openquake.org or https://www.openquake.org:8000.
    """
    if request.is_secure():
        base_url = 'https://%s'
    else:
        base_url = 'http://%s'
    base_url %= request.META['HTTP_HOST']
    return base_url

def _calc_to_response_data(calc):
    """
    Extract the calculation parameters into a dictionary.
    """
    fields = [x.name for x in calc._meta.fields if x.name not in IGNORE_FIELDS]
    response_data = {}
    for field_name in fields:
        try:
            value = getattr(calc, field_name)
            if value is not None:
                if field_name in GEOM_FIELDS:
                    response_data[field_name] = json.loads(value.geojson)
                elif field_name in RISK_INPUTS:
                    response_data[field_name] = value.id
                else:
                    response_data[field_name] = value
        except AttributeError:
            # Better that we miss an attribute than crash.
            pass
    return response_data

def create_detect_job_file(*candidates):
    def detect_job_file(files):
        for candidate in candidates:
            try:
                file_idx = [os.path.basename(f)
                            for f in files].index(candidate)
                return files[file_idx]
            except ValueError:
                pass
        raise RuntimeError("No job file found in %s for %s" % (
            str(files), str(candidates)))
    return detect_job_file

def _prepare_job(request, hazard_output_id, hazard_job_id,
                 detect_job_file):
    """
    Creates a temporary directory, move uploaded files there and
    select the job file by using the `detect_job_file` callable which
    accepts in input a list holding all the filenames ending with .ini

    :returns: job_file and temp_dir
    """
    temp_dir = tempfile.mkdtemp()
    files = []

    try:
        archive = zipfile.ZipFile(request.FILES['archive'])
    except KeyError:
        # move each file to a new temp dir, using the upload file names,
        # not the temporary ones
        for each_file in request.FILES.values():
            new_path = os.path.join(temp_dir, each_file.name)
            shutil.move(each_file.temporary_file_path(), new_path)
            files.append(new_path)
    else:  # extract the files from the archive into temp_dir
        archive.extractall(temp_dir)
        archive.close()
        for fname in os.listdir(temp_dir):
            files.append(os.path.join(temp_dir, fname))
    job_file = detect_job_file([f for f in files if f.endswith('.ini')])
    return job_file, temp_dir

def _is_source_model(tempfile):
    """
    Return true if an uploaded NRML file is a seismic source model.
    """
    tree = etree.iterparse(tempfile, events=('start', 'end'))
    # pop off the first elements, which should be a <nrml> element
    # and something else
    _, nrml_elem = tree.next()
    _, model_elem = tree.next()

    assert nrml_elem.tag == '{%s}nrml' % nrml.NAMESPACE, (
        "Input file is not a NRML artifact"
    )

    if model_elem.tag == '{%s}sourceModel' % nrml.NAMESPACE:
        return True
    return False

@require_http_methods(['GET'])
@cross_domain_ajax
def calc_info(request, job_type, calc_id):
    """
    Get a JSON blob containing all of parameters for the given calculation
    (specified by ``calc_id``). Also includes the current job status (
    executing, complete, etc.).
    """
    try:
        response_data = _get_calc_info(job_type, calc_id)
    except ObjectDoesNotExist:
        return HttpResponseNotFound()

    return HttpResponse(content=json.dumps(response_data), content_type=JSON)

# helper function to get job info and calculation params from the
# oq-engine DB, as a dictionary
def _get_calc_info(job_type, calc_id):
    if job_type == 'hazard':
        job = oqe_models.OqJob.objects.select_related().get(pk=calc_id)
        calc = job.get_oqparam()
    else:  # risk
        job = oqe_models.OqJob.objects.select_related()\
            .get(risk_calculation=calc_id)
        calc = job.risk_calculation

    response_data = _calc_to_response_data(calc)
    response_data['status'] = job.status
    return response_data

@require_http_methods(['GET'])
@cross_domain_ajax
def calc(request, job_type):
    """
    Get a list of calculations and report their id, status, description,
    and a url where more detailed information can be accessed.

    Responses are in JSON.
    """
    base_url = _get_base_url(request)

    calc_data = _get_calcs(job_type)
    if not calc_data:
        return HttpResponseNotFound()

    response_data = []
    for hc_id, status, desc in calc_data:
        url = urlparse.urljoin(base_url, 'v1/calc/%s/%d' % (job_type, hc_id))
        response_data.append(
            dict(id=hc_id, status=status, description=desc, url=url)
        )

    return HttpResponse(content=json.dumps(response_data),
                        content_type=JSON)

@csrf_exempt
@cross_domain_ajax
@require_http_methods(['POST'])
def run_calc(request, job_type):
    """
    Run a calculation.

    :param request:
        a `django.http.HttpRequest` object.
    :param job_type:
        string 'hazard' or 'risk'
    """
    callback_url = request.POST.get('callback_url')
    foreign_calc_id = request.POST.get('foreign_calculation_id')

    hazard_output_id = request.POST.get('hazard_output_id')
    hazard_job_id = request.POST.get('hazard_job_id')

    is_risk = hazard_output_id or hazard_job_id
    if is_risk:
        detect_job_file = create_detect_job_file("job_risk.ini")
    else:
        detect_job_file = create_detect_job_file("job_hazard.ini", "job.ini")
    einfo, exctype = safely_call(
        _prepare_job, (request, hazard_output_id, hazard_job_id,
                       detect_job_file))
    if exctype:
        tasks.update_calculation(callback_url, status="failed", einfo=einfo)
        raise exctype(einfo)
    else:
        job_file, temp_dir = einfo
    job, _fut = submit_job(job_file, temp_dir, request.POST['database'],
                           callback_url, foreign_calc_id,
                           hazard_output_id, hazard_job_id)
    try:
        response_data = _get_calc_info(job_type, job.calc_id)
    except ObjectDoesNotExist:
        return HttpResponseNotFound()

    return HttpResponse(content=json.dumps(response_data), content_type=JSON)

def submit_job(job_file, temp_dir, dbname,
               callback_url=None, foreign_calc_id=None,
               hazard_output_id=None, hazard_job_id=None,
               logfile=None):
    """
    Create a job object from the given job.ini file in the job directory
    and submit it to the job queue.
    """
    job, exctype = safely_call(
        oq_engine.job_from_file, (job_file, "platform", DEFAULT_LOG_LEVEL, [],
                                  hazard_output_id, hazard_job_id))
    if exctype:
        tasks.update_calculation(callback_url, status="failed", einfo=job)
        raise exctype(job)

    future = executor.submit(
        tasks.safely_call, tasks.run_calc, job.job_type, job.id, temp_dir,
        callback_url, foreign_calc_id, dbname, logfile)
    return job, future

def _get_calcs(job_type):
    """
    Helper function for get job+calculation data from the oq-engine database.

    Gets all calculation records available.
    """
    job_params = oqe_models.JobParam.objects.filter(
        name='description', job__risk_calculation__isnull=job_type == 'hazard',
        job__user_name='platform')
    if job_type == 'risk':
        return [(jp.job.risk_calculation, jp.job.status, jp.value)
                for jp in job_params]
    else:  # hazard
        return [(jp.job, jp.job.status, jp.value) for jp in job_params]

@require_http_methods(['GET'])
@cross_domain_ajax
def calc_results(request, job_type, calc_id):
    """
    Get a summarized list of calculation results for a given ``calc_id``.
    Result is a JSON array of objects containing the following attributes:

        * id
        * name
        * type (hazard_curve, hazard_map, etc.)
        * url (the exact url where the full result can be accessed)
    """
    # If the specified calculation doesn't exist OR is not yet complete,
    # throw back a 404.
    try:
        if job_type == 'risk':
            oqjob = oqe_models.RiskCalculation.objects.get(id=calc_id).oqjob
        else:
            oqjob = oqe_models.OqJob.objects.get(id=calc_id)
        if not oqjob.status == 'complete':
            return HttpResponseNotFound()
    except ObjectDoesNotExist:
        return HttpResponseNotFound()
    base_url = _get_base_url(request)

    results = oq_engine.get_outputs(job_type, calc_id)
    if not results:
        return HttpResponseNotFound()

    response_data = []
    for result in results:
        url = urlparse.urljoin(base_url,
                               'v1/calc/%s/result/%d' % (job_type, result.id))
        datum = dict(
            id=result.id,
            name=result.display_name,
            type=result.output_type,
            url=url,
        )
        response_data.append(datum)

    return HttpResponse(content=json.dumps(response_data))

@cross_domain_ajax
@require_http_methods(['GET'])
def get_result(request, job_type, result_id):
    """
    Download a specific result, by ``result_id``.

    Parameters for the GET request can include an `export_type`, such as 'xml',
    'geojson', 'csv', etc.
    """
    return _get_result(
        request, result_id,
        risk_export.export if job_type == 'risk' else hazard_export.export)

def _get_result(request, result_id, export_fn):
    """
    The common abstracted functionality for getting hazard or risk results.
    The functionality is the same, except for the hazard/risk specific
    ``export_fn``.

    :param request:
        `django.http.HttpRequest` object. Can contain a `export_type` GET
        param (the default is 'xml' if no param is specified).
    :param result_id:
        The id of the requested artifact.
    :param export_fn:
        Export function, which accepts the following params:

            * result_id (int)
            * target (a file path or file-like)
            * export_type (option kwarg)

    :returns:
        If the requested ``result_id`` is not available in the format
        designated by the `export_type`.

        Otherwise, return a `django.http.HttpResponse` containing the content
        of the requested artifact.
    """
    # If the result for the requested ID doesn't exist, OR
    # the job which it is related too is not complete,
    # throw back a 404.
    try:
        output = oqe_models.Output.objects.get(id=result_id)
        job = output.oq_job
        if not job.status == 'complete':
            return HttpResponseNotFound()
    except ObjectDoesNotExist:
        return HttpResponseNotFound()

    export_type = request.GET.get('export_type', DEFAULT_EXPORT_TYPE)

    content = StringIO.StringIO()
    try:
        content = export_fn(result_id, content, export_type=export_type)
    except NotImplementedError, err:
        # Throw back a 404 if the exact export parameters are not supported
        return HttpResponseNotFound(err.message)

    # Just in case the original StringIO object was closed:
    resp_content = StringIO.StringIO()
    # NOTE(LB): We assume that `content` was written to by using normal
    # file-like `write` calls; thus, the buflist should be populated with all
    # of the content. The exporter/writer might have closed the file object (if
    # so, we cannot read from it normally) so instead we should look at the
    # buflist.
    # NOTE(LB): This might be a really stupid implementation, but it's the best
    # I could come up with so far.
    resp_content.writelines(content.buflist)
    del content

    # TODO(LB): A possible necessary optimization--in the future--would be to
    # iteratively stream large files.
    # TODO(LB): Large files could pose a memory consumption problem.
    # TODO(LB): We also may want to limit the maximum file size of results sent
    # via http.
    resp_value = resp_content.getvalue()
    resp_content.close()
    # TODO: Need to look at `content_type`, otherwise XML gets treated at HTML
    # in the browser
    content_type = EXPORT_CONTENT_TYPE_MAP.get(export_type,
                                               DEFAULT_CONTENT_TYPE)
    return HttpResponse(resp_value, content_type=content_type)
<|endoftext|>


<commit_before>import os
import hadoopstack
from time import sleep

def get_resv_obj(conn, resv_id):
	'''
	Most of the object values have to be updated to get the most recent values.
	This function takes care of it. As of now, only updated reservation objects
	are required.

	@param resv_obj: Its the reservation object
	@return resv_obj

	'''

	for res in conn.get_all_instances():
		if res.id == resv_obj.id:
			return res

def update_private_ip_address(conn, data):

	for node in data['job']['nodes']:
		if node['private_ip_address'] is None:
			node_resv_obj = get_resv_obj(conn, node['reservation_id'])
			while node_resv_obj.private_ip_address is None:
				sleep(2)
				print "updating node {0} private ip address".format(node['id'])
				get_resv_obj(conn, node_resv_obj)

			node[private_ip_address] = node_resv_obj.private_ip_address
			flush_data_to_mongo('job', data)

def get_node_objects(conn, role, resv_id=None):

	nodes = list()
	for resv in conn.get_all_instances():
		if resv.id == resv_id:
			for instance in resv.instances:
				node = dict()
				node['id'] = instance.id
				node['private_ip_address'] = instance.private_ip_address
				node['reservation_id'] = resv_id
				node['role'] = role
				nodes.append(node)
	print nodes
	return nodes

def flush_data_to_mongo(db_name, data_dict):

	if db_name == "job":
		hadoopstack.main.mongo.db.job.save(data_dict)

	if db_name == "job":
		hadoopstack.main.mongo.db.job.save(data_dict)
<commit_msg>Added flavor in node object<commit_after>import os
import hadoopstack
from time import sleep

def get_resv_obj(conn, resv_id):
	'''
	Most of the object values have to be updated to get the most recent values.
	This function takes care of it. As of now, only updated reservation objects
	are required.

	@param resv_obj: Its the reservation object
	@return resv_obj

	'''

	for res in conn.get_all_instances():
		if res.id == resv_obj.id:
			return res

def update_private_ip_address(conn, data):

	for node in data['job']['nodes']:
		if node['private_ip_address'] is None:
			node_resv_obj = get_resv_obj(conn, node['reservation_id'])
			while node_resv_obj.private_ip_address is None:
				sleep(2)
				print "updating node {0} private ip address".format(node['id'])
				get_resv_obj(conn, node_resv_obj)

			node[private_ip_address] = node_resv_obj.private_ip_address
			flush_data_to_mongo('job', data)

def get_node_objects(conn, role, resv_id=None):

	nodes = list()
	for resv in conn.get_all_instances():
		if resv.id == resv_id:
			for instance in resv.instances:
				node = dict()
				node['id'] = instance.id
				node['private_ip_address'] = instance.private_ip_address
				node['reservation_id'] = resv_id
				node['role'] = role
				node['flavor'] = instance.instance_type
				nodes.append(node)
	print nodes
	return nodes

def flush_data_to_mongo(db_name, data_dict):

	if db_name == "job":
		hadoopstack.main.mongo.db.job.save(data_dict)

	if db_name == "job":
		hadoopstack.main.mongo.db.job.save(data_dict)
<|endoftext|>


<commit_before>__author__ = 'sachinpatney'

import sys
sys.path.append('/var/www/git/redalert/tasks')
sys.path.append('/var/www/git/redalert/hardware/watcher/actions')

import serial
import time
import binascii
from test_action import LetsParty

ser = serial.Serial('/dev/ttyUSB0', baudrate=9600, timeout=1.0)
s = b''

def do(command):
    if command == 'party':
        LetsParty().__do__()

do('party')

sys.exit(0)

while True:
        bytesToRead = ser.inWaiting()

        if bytesToRead > 0:
            s += ser.read()
            if binascii.hexlify(s) == b'7e':
                w = ser.read(2)
                s += w
                l = int(binascii.hexlify(w), 16)
                s += ser.read(l + 2)
                s = binascii.hexlify(s)

                if s[6:8] == b'90':  # Receive Request, checksum verification not needed.
                    data = s[32:-2]
                    data = binascii.unhexlify(data).decode('utf-8').strip('\0')
                    do(data)
            else:
                s = b''
        else:
            s = b''
            time.sleep(0.3)<commit_msg>Update zb_watcher.py<commit_after>__author__ = 'sachinpatney'

import sys
sys.path.append('/var/www/git/redalert/tasks')
sys.path.append('/var/www/git/redalert/hardware/watcher/actions')

import serial
import time
import binascii
from test_action import LetsParty

ser = serial.Serial('/dev/ttyUSB0', baudrate=9600, timeout=1.0)
s = b''

def do(command):
    if command == 'party':
        LetsParty().__do__()
    if command == 'play':
        print('playing ... ')

while True:
        bytesToRead = ser.inWaiting()

        if bytesToRead > 0:
            s += ser.read()
            if binascii.hexlify(s) == b'7e':
                w = ser.read(2)
                s += w
                l = int(binascii.hexlify(w), 16)
                s += ser.read(l + 2)
                s = binascii.hexlify(s)

                if s[6:8] == b'90':  # Receive Request, checksum verification not needed.
                    data = s[32:-2]
                    data = binascii.unhexlify(data).decode('utf-8').strip('\0')
                    do(data)
            else:
                s = b''
        else:
            s = b''
            time.sleep(0.3)
<|endoftext|>