Full Code of rolandoislas/drc-sim for AI

master c32586c8fa58 cached
49 files
111.0 KB
27.4k tokens
152 symbols
1 requests
Download .txt
Repository: rolandoislas/drc-sim
Branch: master
Commit: c32586c8fa58
Files: 49
Total size: 111.0 KB

Directory structure:
gitextract_j_pnps2_/

├── .gitignore
├── .travis.yml
├── Dockerfile
├── MANIFEST.in
├── drc-info.py
├── drc-sim-backend
├── install.sh
├── license.txt
├── readme.md
├── resources/
│   ├── bin/
│   │   └── drcsimbackend.desktop
│   └── config/
│       └── get_psk.conf
├── setup.py
├── src/
│   ├── __init__.py
│   └── server/
│       ├── __init__.py
│       ├── data/
│       │   ├── __init__.py
│       │   ├── args.py
│       │   ├── config.py
│       │   ├── config_general.py
│       │   ├── constants.py
│       │   ├── resource.py
│       │   └── struct/
│       │       ├── __init__.py
│       │       ├── command.py
│       │       └── input.py
│       ├── ui/
│       │   ├── __init__.py
│       │   ├── cli/
│       │   │   ├── __init__.py
│       │   │   └── cli_main.py
│       │   └── gui/
│       │       ├── __init__.py
│       │       ├── frame/
│       │       │   ├── __init__.py
│       │       │   ├── frame_about.py
│       │       │   ├── frame_get_key.py
│       │       │   ├── frame_log.py
│       │       │   ├── frame_run_server.py
│       │       │   └── frame_tab.py
│       │       └── gui_main.py
│       └── util/
│           ├── __init__.py
│           ├── drc_sim_c.py
│           ├── interface_util.py
│           ├── logging/
│           │   ├── __init__.py
│           │   ├── logger.py
│           │   ├── logger_backend.py
│           │   ├── logger_cli.py
│           │   ├── logger_gui.py
│           │   └── logger_wpa.py
│           ├── os_util.py
│           ├── process_util.py
│           ├── status_sending_thread.py
│           └── wpa_supplicant.py
└── tests/
    ├── packets/
    │   └── .gitignore
    └── test_parse.py

================================================
FILE CONTENTS
================================================

================================================
FILE: .gitignore
================================================
__pycache__/
*.pyc
.idea/
.pypy/
build/
dist/
*.egg-info/
setup.cfg
temp/
.drc-sim/
region_dump.json
*.bin
.cache/


================================================
FILE: .travis.yml
================================================
language: python
python:
  - "3.4"
  - "3.5"
  - "3.6"
dist: trusty
sudo: required
install:
  - sudo apt-get -qq update
  - sudo ./install.sh local
before_script:
  - export PYTHONPATH=$(pwd)
script: pytest

================================================
FILE: Dockerfile
================================================
FROM debian:jessie

ADD drc-sim-backend /root/
ADD setup.py /root/
ADD src/ /root/src/
ADD resources/ /root/resources/
ADD MANIFEST.in /root/
ADD install.sh /root/

RUN apt-get update \
    && cd /root/ \
    && ./install.sh local

ENV TERM xterm
ENTRYPOINT ["drc-sim-backend", "--cli"]
CMD ["-h"]


================================================
FILE: MANIFEST.in
================================================
recursive-include src *

================================================
FILE: drc-info.py
================================================
import codecs
import json
import select
import socket
import sys
import time
from threading import Thread

from src.server.data.struct import input, command

PORT_WII_MSG = 50010
PORT_WII_VID = 50020
PORT_WII_AUD = 50021
PORT_WII_HID = 50022
PORT_WII_CMD = 50023

sock_cmd = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock_cmd.bind(("192.168.1.10", PORT_WII_CMD))
sock_msg = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock_msg.bind(("192.168.1.10", PORT_WII_MSG))
sock_hid = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock_hid.bind(("192.168.1.10", PORT_WII_HID))
sock_vid = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock_vid.bind(("192.168.1.10", PORT_WII_VID))
sock_aud = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock_aud.bind(("192.168.1.10", PORT_WII_AUD))

json_dump = {}


def print_packet(sock, name):
    data = sock.recv(2048)
    print("%s: %s" % (name, codecs.encode(data, "hex").decode()))


def print_packet_cmd(sock):
    data = sock.recv(2048)
    print("cmd: %s" % codecs.encode(data, "hex").decode())
    header = command.header.parse(data)
    if header.packet_type != 2:  # Only accept response packets
        return
    size = 8  # header size
    if header.cmd_id == 1:
        data_string = codecs.encode(data[size:], "hex").decode()
        print("cmd 1: %s" % data_string)
        json_dump["1"] = data_string
    elif header.cmd_id == 0:
        data_string = codecs.encode(data[size + command.header_cmd0.sizeof():], "hex").decode()
        print("cmd 0 %d %d: %s" % (header.id_primary, header.id_secondary, data_string))
        if "0" not in json_dump:
            json_dump["0"] = {}
        if str(header.id_primary) not in json_dump["0"]:
            json_dump["0"][str(header.id_primary)] = {}
        json_dump["0"][str(header.id_primary)][str(header.id_secondary)] = data_string


def send_cmd(data):
    sock_cmd.sendto(data, ("192.168.1.11", PORT_WII_CMD + 100))


def send_command_from_string(command_string, sid):
    send_data = command.header.parse(codecs.decode(command_string, "hex"))
    send_data.seq_id = sid
    if send_data.cmd_id == 1:
        send_data.mic_enabled = 0  # floods logs with audio data if enabled
    send_data = command.header.build(send_data)
    send_cmd(send_data)
    sid += 1
    sid %= 65535
    time.sleep(1)
    return sid


def cmd_request():
    sid = 0
    while True:
        data = {
            0: {0: {0: "000000000c0005087e0115880040000000000000",  # TODO construct these
                    10: "000000000d0005007e0101780040000a0000000100"},
                4: {4: "000000000c0005007e0109780040040400000000",
                    10: "000000000d0005117e012fc80040040a0000000100",
                    11: "000000000c0005017e0107180040040b00000000"},
                5: {6: "000000000c0005007e0101a80040050600000000",
                    12: "00000000110005007e0102f80040050c000000050e0300870f",
                    16: "0000010030000580010000000000000000000000803e0000000100029e0000000000000070000000404003002d0000"
                        "018000400000000000",  # FIXME 0 5 16 is a CMD 1 broadcast - missing actual request
                    24: "00000000160005007e0101c8004005180000000a54313936333030303030"}
                },
            1: "000001003000051a010000000000000000000000803e000000010002000000000000000070000000404003002d00000"
               "10000000000000000"
        }
        for cmd in data.keys():
            if isinstance(data[cmd], str):
                print("Sending command %d" % cmd)
                sid = send_command_from_string(data[cmd], sid)
            else:
                for primary_id in data[cmd].keys():
                    for secondary_id in data[cmd][primary_id].keys():
                        print("Sending command %d %d %d" % (cmd, primary_id, secondary_id))
                        sid = send_command_from_string(data[cmd][primary_id][secondary_id], sid)


def print_hid(sock):
    data = sock.recv(2048)
    input_parsed = input.input_data.parse(data)
    print(input_parsed)


if __name__ == '__main__':
    hid = len(sys.argv) > 1 and sys.argv[1] == "--hid"

    if not hid:
        send_thread = Thread(target=cmd_request)
        send_thread.daemon = True
        send_thread.start()

    while True:
        try:
            rlist, wlist, xlist = select.select((sock_cmd, sock_msg, sock_hid, sock_vid, sock_aud), (), (), 1)
            if rlist:
                for s in rlist:
                    if s == sock_hid and hid:
                        print_hid(s)
                    if hid:
                        continue
                    if s == sock_aud:
                        print_packet(s, "aud")
                    elif s == sock_vid:
                        print_packet(s, "vid")
                    elif s == sock_cmd:
                        print_packet_cmd(s)
                    elif s == sock_msg:
                        print_packet(s, "msg")
        except KeyboardInterrupt:
            if not hid:
                dump = open("region_dump.json", "w")
                dump.write(json.dumps(json_dump, indent=4))
                dump.close()
                print("Wrote dump to region_dump.json")
            sys.exit(0)


================================================
FILE: drc-sim-backend
================================================
#!/usr/bin/env python3
import os
import sys

from src.server.data import constants
from src.server.data.args import Args
from src.server.data.config_general import ConfigGeneral
from src.server.ui.cli.cli_main import CliMain
from src.server.util.logging.logger import Logger
from src.server.util.logging.logger_backend import LoggerBackend
from src.server.util.logging.logger_cli import LoggerCli
from src.server.util.logging.logger_gui import LoggerGui
from src.server.util.logging.logger_wpa import LoggerWpa
from src.server.util.os_util import OsUtil


def init_loggers():
    """
    Initialize loggers with a specified log level if they have the argument.
    :return: None
    """
    loggers = (Logger, LoggerBackend, LoggerGui, LoggerCli, LoggerWpa)
    for logger in loggers:
        if Args.args.debug:
            logger.set_level(Logger.DEBUG)
        elif Args.args.extra:
            logger.set_level(Logger.EXTRA)
        elif Args.args.finer:
            logger.set_level(Logger.FINER)
        elif Args.args.verbose:
            logger.set_level(Logger.VERBOSE)
        else:
            logger.set_level(Logger.INFO)


def start():
    """
    Main loop. It can be GUI or CLI based on args. Dies if an error makes it way here or main loop stops.
    :return: None
    """
    ui = None
    try:
        if Args.args.cli:
            Logger.info("Enabling CLI")
            ui = CliMain()
        else:
            Logger.info("Enabling GUI")
            from src.server.ui.gui.gui_main import GuiMain
            ui = GuiMain()
        ui.start()
    except KeyboardInterrupt:
        if ui:
            ui.stop()
    except Exception as e:
        if ui:
            ui.stop()
        Logger.exception(e)
    Logger.info("Exiting")


def log_level():
    """
    Log at every level to display the levels that are enabled.
    :return: None
    """
    # Logger info
    Logger.debug("Debug logging enabled")
    Logger.extra("Extra debug logging enabled")
    Logger.finer("Finer debug logging enabled")
    Logger.verbose("Verbose logging enabled")
    if LoggerWpa.get_level() <= Logger.FINER:
        LoggerWpa.warn("At this log level SSIDs are logged!")


def check_root():
    """
    Exit if not root
    :return: 
    """
    if os.getuid() != 0:
        Logger.throw("Not running as root!")
        sys.exit()
    else:
        Logger.extra("I am root!")


def main():
    """
    Main entry point. Parses arguments, loads configuration files, initialized loggers and starts the main loop.
    :return: None
    """
    Args.parse_args()
    ConfigGeneral.load()
    ConfigGeneral.save()
    init_loggers()
    check_root()
    Logger.info("Initializing drc-sim-backend version %s", constants.VERSION)
    Logger.info("Using \"%s\" as home folder.", constants.PATH_ROOT)
    log_level()
    OsUtil.log_info(Logger)
    start()


if __name__ == '__main__':
    main()


================================================
FILE: install.sh
================================================
#!/usr/bin/env bash
# drc-sim(-backend): Wii U gamepad emulator.
#
# drc-sim-backend install script
# https://github.com/rolandoislas/drc-sim
#
# Changelog
#
# June 1, 2017 - 1.1
#    Add output on error for make, cmake, and setup.py
#    Add setup.py outputs to install.txt during install and it is read from for an uninstall
#    Move init script, desktop launcher, and icon to setup.py
#    Add version number
#    Add pkg-info - wpa_supplicant compile fails without it
#    Remove virtualenv
# June 1, 2017 - 1.1.1
#    Fix Make, cmake, and setup.py not returning on errors
#    Fix current directory not being restored on a git update failure
# June 2, 2017 - 1.1.2
#    Detect and install to virtualenv
# June 3, 2017 - 1.1.3
#    Use python3 from virtualenv if found

VERSION="1.1.3"
REPO_DRC_SIM="https://github.com/rolandoislas/drc-sim.git"
REPO_WPA_SUPPLICANT_DRC="https://github.com/rolandoislas/drc-hostap.git"
REPO_DRC_SIM_C="https://github.com/rolandoislas/drc-sim-c.git"
INSTALL_DIR="/opt/drc_sim/"
dependencies=()
branch_drc_sim=""

# Checks to see if OS has apt-get and sets dependencies
# Exits otherwise
check_os() {
    if command -v apt-get &> /dev/null; then
        echo "Command apt-get found."
        # Backend dependencies
        dependencies=("python3" "python3-pip"
        "net-tools" "wireless-tools" "sysvinit-utils" "psmisc" "rfkill"
        "isc-dhcp-client" "ifmetric" "python3-tk" "gksu")
        # Wpa supplicant compile dependencies
        dependencies+=("git" "libssl-dev" "libnl-genl-3-dev" "gcc" "make" "pkg-config")
        # DRC Sim Server C++
        dependencies+=("libavcodec-dev" "libswscale-dev" "libjpeg-dev" "cmake")
    else
        echo "The command apt-get was not found. This OS is not supported."
        exit 1
    fi
}

# Check to see if the script is running as root
# Exits if not root
check_root() {
    if [[ ${EUID} -ne 0 ]]; then
        echo "Install script must be executed with root privileges."
        exit 1
    fi
}

# Checks and installs pre-defined decencies array
# Exits on failed dependency
install_dependencies() {
    echo "Installing dependencies."
    for dependency in "${dependencies[@]}"
    do
        installed="$(dpkg -s ${dependency} 2>&1)"
        if [[ ${installed} =~ "Status: install ok installed" ]]; then
            echo "${dependency} [INSTALLED]"
        else
            echo "${dependency} [INSTALLING]"
            if command apt-get -y install ${dependency} &> /dev/null; then
                echo "${dependency} [INSTALLED]"
            else
                echo "${dependency} [FAILED]"
                exit 1
            fi
        fi
    done
}

# Update git directory while stashing changed return 1
# Returns 1 on failure
update_git() {
    cur_dir="${PWD}"
    cd "${1}" &> /dev/null || return 1
    if [[ -d "${1}" ]]; then
        echo "Found existing git directory ${1}"
        if command git stash --include-untracked &> /dev/null; then
            echo "Stashed git changes"
            echo "Updating git repo"
            if command git pull &> /dev/null; then
                echo "Updated git repo"
            else
                cd "${cur_dir}" &> /dev/null || return 1
                return 1
            fi
        else
            cd "${cur_dir}" &> /dev/null || return 1
            return 1
        fi
    fi
    cd "${cur_dir}" &> /dev/null || return 1
    return 0
}

# Clones a git repo to the install path
# If the directory exists it is removed
# Param $1: git repo url
get_git() {
    git_dir="${INSTALL_DIR}${2}"
    if update_git ${git_dir}; then
        return 0
    else
        # Remove directory for a clean clone
        if [[ -d "${git_dir}" ]]; then
            rm -rf "${git_dir}"
        fi
    fi
    # Clone
    echo "Cloning ${1} into ${git_dir}"
    if command git clone ${1} ${git_dir} &> /dev/null; then
        echo "Cloned ${1}"
    else
        echo "Failed to clone ${1}"
        exit 1
    fi
}

# Compiles wpa_supplicant after fetching it from git
compile_wpa() {
    get_git ${REPO_WPA_SUPPLICANT_DRC} "wpa"
    echo "Compiling wpa_supplicant_drc"
    compile_dir="${INSTALL_DIR}wpa/wpa_supplicant/"
    cur_dir="${PWD}"
    cd "${compile_dir}" &> /dev/null || return 1
    cp ../conf/wpa_supplicant.config ./.config &> /dev/null || return 1
    compile_log="${compile_dir}make.log"
    echo "Compile log at ${compile_log}"
    if ! make &> ${compile_log}; then cat "${compile_log}"; return 1; fi
    echo "Installing wpa_supplicant_drc and wpa_cli_drc to /usr/local/bin"
    cp wpa_supplicant /usr/local/bin/wpa_supplicant_drc &> /dev/null || return 1
    cp wpa_cli /usr/local/bin/wpa_cli_drc &> /dev/null || return 1
    cd "${cur_dir}" &> /dev/null || return 1
    return 0
}

# Compiles drc_sim_c after fetching it from git
compile_drc_sim_c() {
    get_git ${REPO_DRC_SIM_C} "drc_sim_c"
    echo "Compiling drc_sim_c"
    compile_dir="${INSTALL_DIR}drc_sim_c/"
    cur_dir="${PWD}"
    cd "${compile_dir}" &> /dev/null || return 1
    compile_log="${compile_dir}make.log"
    cmake_log="${compile_dir}cmake.log"
    echo "Compile log at ${compile_log}"
    if ! cmake "${compile_dir}" &> "${cmake_log}"; then cat "${cmake_log}"; return 1; fi
    if ! make &> "${compile_log}"; then cat "${compile_log}"; return 1; fi
    echo "Installing drc_sim_c to /usr/local/bin"
    make install &> /dev/null || return 1
    cd "${cur_dir}" &> /dev/null || return 1
    return 0
}

# Installs drc-sim in a virtualenv
install_drc_sim() {
    echo "Installing DRC Sim Server GUI/CLI Utility"
    # Paths
    drc_dir="${INSTALL_DIR}drc/"
    cur_dir="${PWD}"
    # Fix virtualenv paths
    prefix=""
    python="python3"
    if [ ! -z "${VIRTUAL_ENV}" ]; then
        echo "Installing into virtualenv: ${VIRTUAL_ENV}"
        prefix="--prefix ${VIRTUAL_ENV}"
        python="${VIRTUAL_ENV}/bin/${python}"
    fi
    # Get source
    if [[ "${branch_drc_sim}" != "local" ]]; then
        # Get repo
        get_git ${REPO_DRC_SIM} "drc"
    else
        # Copy local
        if [[ ! -f "${cur_dir}/setup.py" ]]; then
            echo "Cannot perform local install. Missing source files at ${cur_dir}."
            return 1
        fi
        if [[ ! -d "${INSTALL_DIR}" ]]; then
            mkdir "${INSTALL_DIR}" &> /dev/null || return 1
        fi
        rm -rf ${drc_dir} &> /dev/null || return 1
        mkdir ${drc_dir} &> /dev/null || return 1
        cp -R "${cur_dir}/." "${drc_dir%/*}" &> /dev/null || return 1
    fi
    # Install python dependencies
    echo "Installing setuptools"
    ${python} -m pip install setuptools &> /dev/null || return 1
    # Remove an existing install of drc-sim
    echo "Attempting to remove previous installations"
    ${python} -m pip uninstall -y drcsim &> /dev/null || \
        echo "Failed to remove the previous installation. Attempting to install anyway."
    # Set the directory
    cd "${drc_dir}" &> /dev/null || return 1
    # Branch to checkout
    if [[ "${branch_drc_sim}" != "local" ]]; then
        echo "Using branch \"${branch_drc_sim}\" for drc-sim install"
        git checkout ${branch_drc_sim} &> /dev/null || return 1
    else
        echo "Using current directory as install source"
    fi
    # Install
    echo "Installing drc-sim"
    echo "Downloading Python packages. This may take a while."
    if ! ${python} "${drc_dir}setup.py" install ${prefix} --record "${drc_dir}/install.txt" &> \
        "/tmp/drc-sim-py-install.log"; then
        cat "/tmp/drc-sim-py-install.log"
        return 1
    fi
    cd "${cur_dir}" &> /dev/null || return 1
    # Update icon cache
    update-icon-caches /usr/share/icons/* &> /dev/null || echo "Failed to update icon cache."
}

# Echos the general info
print_info() {
    echo "Drc-sim installer (script version ${VERSION})"
    printf "\thttps://github.com/rolandoislas/drc-sim\n"
}

# Uninstalls DRC Sim then exists
uninstall() {
    drc_install_log="${INSTALL_DIR}drc/install.txt"
    echo "Uninstalling DRC Sim Server"
    # Remove setup.py files
    if [[ -f "${drc_install_log}" ]]; then
        echo "Files to remove:"
        cat ${drc_install_log}
        read -p "Remove these files? [Y/N]" reponse
        if [[ ${reponse} =~ [Yy](es)* ]]; then
            tr '\n' '\0' < ${drc_install_log} | xargs -0 sudo rm -f --
            echo "Removed Python installed files"
        else
            echo "Not removing Python installed files"
            echo "Install canceled"
            exit 2
        fi
    else
        echo "Could not clean Python installed files. Missing ${drc_install_log}"
    fi
    # Launcher (.desktop)
    to_remove=("/usr/share/applications/drc-sim-backend.desktop" "/usr/share/applications/drcsimbackend.desktop"
        "/usr/share/icons/hicolor/512x512/apps/drcsimbackend.png")
    for item in "${to_remove[@]}"; do
        if [[ -f "${item}" ]]; then
            rm -f ${item} &> /dev/null
        fi
    done
    # Install dir
    echo "Removing install directory"
    rm -rf ${INSTALL_DIR} &> /dev/null || echo "Failed to remove install directory."
    # TODO uninstall packages
    printf "\nNOT removing package dependencies\n"
    printf "${dependencies[*]}\n\n"
    # Done
    echo "Uninstalled DRC Sim Server"
    exit 0
}

# Parses args
check_args() {
    branch_drc_sim=${1:-master}
    # Help
    if [[ "${1}" == "help" ]] || [[ "${1}" == "-h" ]]; then
        echo "Usage: <install.sh> [argument]"
        echo "  Defaults to install."
        echo "  Arguments:"
        echo "    -h, help : help menu"
        echo "    branch : branch to use for drc-sim (master, develop, local) master is used by default"
        echo "    uninstall : uninstall DRC Sim"
        exit 1
    # Uninstall
    elif [[ "${1}" == "uninstall" ]]; then
        uninstall
    # Install branch
    elif [[ "${branch_drc_sim}" != "develop" ]] && [[ "${branch_drc_sim}" != "master" ]] && 
         [[ "${branch_drc_sim}" != "local" ]]; then
        echo "Invalid branch \"${1}\""
        check_args "help"
    fi
}

# Check if command return value is non-zero and exit with message.
# If the command exited with a zero exit value the success message will be echoed
pass_fail() {
    if $1; then
        echo $2
    else
        echo $3
        exit 1
    fi
}

# Echo post install message and exit
post_install() {
    echo "Install finished"
    echo "\"DRC SIM Server\" will now appear in GUI application menus."
    echo "It can also be launched via \"drc-sim-backend\"."
    exit 0
}

# Install drc_sim
install() {
    install_dependencies
    pass_fail compile_wpa "Compiled wpa_supplicant" "Failed to compile wpa_supplicant"
    pass_fail compile_drc_sim_c "Compiled drc_sim_c" "Failed to compile drc_sim_c"
    pass_fail install_drc_sim "Installed drc-sim" "Failed to install drc-sim"
    post_install
}

main() {
    print_info
    check_root
    check_os
    check_args "$@"
    install
}


main "$@"


================================================
FILE: license.txt
================================================
Copyright (C) 2017 Rolando Islas

This file is part of DRC Sim Server.

DRC Sim Server is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.

DRC Sim Server is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with DRC Sim Server.  If not, see <http://www.gnu.org/licenses/>.

---------------------------------------------------------------------------

                    GNU GENERAL PUBLIC LICENSE
                       Version 2, June 1991

 Copyright (C) 1989, 1991 Free Software Foundation, Inc., <http://fsf.org/>
 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 Everyone is permitted to copy and distribute verbatim copies
 of this license document, but changing it is not allowed.

                            Preamble

  The licenses for most software are designed to take away your
freedom to share and change it.  By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users.  This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it.  (Some other Free Software Foundation software is covered by
the GNU Lesser General Public License instead.)  You can apply it to
your programs, too.

  When we speak of free software, we are referring to freedom, not
price.  Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.

  To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.

  For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have.  You must make sure that they, too, receive or can get the
source code.  And you must show them these terms so they know their
rights.

  We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.

  Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software.  If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.

  Finally, any free program is threatened constantly by software
patents.  We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary.  To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.

  The precise terms and conditions for copying, distribution and
modification follow.

                    GNU GENERAL PUBLIC LICENSE
   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION

  0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License.  The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language.  (Hereinafter, translation is included without limitation in
the term "modification".)  Each licensee is addressed as "you".

Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope.  The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.

  1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.

You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.

  2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:

    a) You must cause the modified files to carry prominent notices
    stating that you changed the files and the date of any change.

    b) You must cause any work that you distribute or publish, that in
    whole or in part contains or is derived from the Program or any
    part thereof, to be licensed as a whole at no charge to all third
    parties under the terms of this License.

    c) If the modified program normally reads commands interactively
    when run, you must cause it, when started running for such
    interactive use in the most ordinary way, to print or display an
    announcement including an appropriate copyright notice and a
    notice that there is no warranty (or else, saying that you provide
    a warranty) and that users may redistribute the program under
    these conditions, and telling the user how to view a copy of this
    License.  (Exception: if the Program itself is interactive but
    does not normally print such an announcement, your work based on
    the Program is not required to print an announcement.)

These requirements apply to the modified work as a whole.  If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works.  But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.

Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.

In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.

  3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:

    a) Accompany it with the complete corresponding machine-readable
    source code, which must be distributed under the terms of Sections
    1 and 2 above on a medium customarily used for software interchange; or,

    b) Accompany it with a written offer, valid for at least three
    years, to give any third party, for a charge no more than your
    cost of physically performing source distribution, a complete
    machine-readable copy of the corresponding source code, to be
    distributed under the terms of Sections 1 and 2 above on a medium
    customarily used for software interchange; or,

    c) Accompany it with the information you received as to the offer
    to distribute corresponding source code.  (This alternative is
    allowed only for noncommercial distribution and only if you
    received the program in object code or executable form with such
    an offer, in accord with Subsection b above.)

The source code for a work means the preferred form of the work for
making modifications to it.  For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable.  However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.

If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.

  4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License.  Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.

  5. You are not required to accept this License, since you have not
signed it.  However, nothing else grants you permission to modify or
distribute the Program or its derivative works.  These actions are
prohibited by law if you do not accept this License.  Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.

  6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions.  You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.

  7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License.  If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all.  For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.

If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.

It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices.  Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.

This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.

  8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded.  In such case, this License incorporates
the limitation as if written in the body of this License.

  9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time.  Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.

Each version is given a distinguishing version number.  If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation.  If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.

  10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission.  For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this.  Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.

                            NO WARRANTY

  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.

  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.

                     END OF TERMS AND CONDITIONS

            How to Apply These Terms to Your New Programs

  If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.

  To do so, attach the following notices to the program.  It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.

    {description}
    Copyright (C) {year}  {fullname}

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License along
    with this program; if not, write to the Free Software Foundation, Inc.,
    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.

Also add information on how to contact you by electronic and paper mail.

If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:

    Gnomovision version 69, Copyright (C) year name of author
    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
    This is free software, and you are welcome to redistribute it
    under certain conditions; type `show c' for details.

The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License.  Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.

You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary.  Here is a sample; alter the names:

  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
  `Gnomovision' (which makes passes at compilers) written by James Hacker.

  {signature of Ty Coon}, 1 April 1989
  Ty Coon, President of Vice

This General Public License does not permit incorporating your program into
proprietary programs.  If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library.  If this is what you want to do, use the GNU Lesser General
Public License instead of this License.

================================================
FILE: readme.md
================================================
DRC Sim Server
---

Stable: [![Build Status](https://travis-ci.org/rolandoislas/drc-sim.svg?branch=master)](https://travis-ci.org/rolandoislas/drc-sim)
Dev: [![Build Status](https://travis-ci.org/rolandoislas/drc-sim.svg?branch=develop)](https://travis-ci.org/rolandoislas/drc-sim)

DRC Sim Server is a utility for pairing a computer to a Wii U to emulate a gamepad.

It needs a [client] for full functionality.

See the [wiki] for more info.

# Installation

[Installation instructions] are available on the wiki.

# Credits

[drc-sim] \(original\) by [memahaxx]
- The original Python codebase

[libdrc documentation] by memahaxx
- Gamepad and Wii U software and hardware details

[drc-sim-keyboard] by justjake
- The readme that got me set up initially

# Additional Software

[wpa_supplicant] modified by memahaxx

[drc_sim_c] drc-sim rewritten in C++

[netifaces] Python network interfaces library

[pexpect] Python process interaction library



[drc-sim]: https://bitbucket.org/memahaxx/drc-sim
[drc-sim-keyboard]: https://github.com/justjake/drc-sim-keyboard
[Installation instructions]: https://github.com/rolandoislas/drc-sim/wiki/Install
[client]: https://github.com/rolandoislas/drc-sim-client/wiki/Home
[wiki]: https://github.com/rolandoislas/drc-sim/wiki/Home
[wpa_supplicant]: https://github.com/rolandoislas/drc-hostap
[drc_sim_c]: https://github.com/rolandoislas/drc-sim-c
[memahaxx]: https://bitbucket.org/memahaxx/
[libdrc documentation]: http://libdrc.org/docs/index.html
[netifaces]: https://pypi.python.org/pypi/netifaces
[pexpect]: https://pypi.python.org/pypi/pexpect

================================================
FILE: resources/bin/drcsimbackend.desktop
================================================
[Desktop Entry]
Version=1.0
Name=DRC SIM Server
Comment=Wii U Gamepad Emulator Backend Server
Exec=gksu /usr/local/bin/drc-sim-backend
Icon=drcsimbackend
Terminal=false
Type=Application
Categories=Game;Network;

================================================
FILE: resources/config/get_psk.conf
================================================
ctrl_interface=/var/run/wpa_supplicant_drc
update_config=1


================================================
FILE: setup.py
================================================
#!/usr/bin/env python3

from distutils.core import setup, Command

from setuptools import find_packages

from src.server.data import constants


class CompileDrcSimC(Command):
    pass  # TODO compile drc_sim_c


class CompileWpaSupplicantDrc(Command):
    pass  # TODO compile wpa_supplicant_drc


setup(name='drcsim',
      version=constants.VERSION,
      description='Wii U gamepad simulator.',
      install_requires=['netifaces>=0.10.5', 'pexpect>=4.2.1'],
      packages=find_packages(),
      include_package_data=True,
      data_files=[
          ('resources/config', [
              'resources/config/get_psk.conf'
          ]),
          ('resources/image', [
              'resources/image/clover.gif',
              'resources/image/diamond.gif',
              'resources/image/heart.gif',
              'resources/image/spade.gif',
              'resources/image/icon.gif'
          ]),
          ('/usr/share/applications', [
              'resources/bin/drcsimbackend.desktop'
          ]),
          ('/usr/share/icons/hicolor/512x512/apps', [
              'resources/image/drcsimbackend.png'
          ])
      ],
      scripts=['drc-sim-backend'],
      cmdclass={
          "compile_drc_sim_c": CompileDrcSimC,
          "compile_wpa_supplicant_drc": CompileWpaSupplicantDrc
      }
      )


================================================
FILE: src/__init__.py
================================================


================================================
FILE: src/server/__init__.py
================================================


================================================
FILE: src/server/data/__init__.py
================================================


================================================
FILE: src/server/data/args.py
================================================
import argparse

import sys

from src.server.data import constants


class Args:
    args = None

    def __init__(self):
        pass

    @staticmethod
    def parse_args():
        arg_parser = argparse.ArgumentParser(description="%s provides an easy launcher for drc_sim_c and "
                                                         "wpa_supplicant_drc" % constants.NAME)
        # Logging
        arg_parser.add_argument("-d", "--debug", action="store_const", const=True, default=False,
                                help="debug output")
        arg_parser.add_argument("-e", "--extra", action="store_const", const=True, default=False,
                                help="extra debug output")
        arg_parser.add_argument("-f", "--finer", action="store_const", const=True, default=False,
                                help="finer debug output")
        arg_parser.add_argument("-v", "--verbose", action="store_const", const=True, default=False,
                                help="verbose debug output")
        arg_parser.add_argument("-c", "--cli", action="store_const", const=True, default=False,
                                help="disable gui")
        # Disable server
        arg_parser.add_argument("--disable-server", "--disable_server", action="store_const", const=True, default=False,
                                help="dev: disable packet handling and serving")
        # CLI
        args = ["-c", "--cli", "-h", "--help"]
        found = False
        for arg in args:
            if arg in sys.argv:
                found = True
        if found:
            subparsers = arg_parser.add_subparsers()
            # Run Server
            run_server = subparsers.add_parser("run_server")
            run_server.add_argument("wii_u_interface", type=str)
            run_server.add_argument("normal_interface", type=str)
            run_server.add_argument("-region", type=str, default="none")
            # Get Key
            get_key = subparsers.add_parser("get_key")
            get_key.add_argument("wii_u_interface", type=str)
            get_key.add_argument("wps_pin", type=str)
        Args.args = arg_parser.parse_args()
        # Add sub arguments
        Args.args.run_server = False
        Args.args.get_key = False
        if "run_server" in sys.argv:
            Args.args.run_server = True
        elif "get_key" in sys.argv:
            Args.args.get_key = True


================================================
FILE: src/server/data/config.py
================================================
import configparser
import os


class Config:

    def __init__(self):
        self.path = ""
        self.config = configparser.ConfigParser(allow_no_value=True)

    def load(self, path):
        self.path = os.path.expanduser(path)
        self.config.read(self.path)

    def get_boolean(self, section, option, default, comment=""):
        try:
            value = self.config.getboolean(section, option)
            self.add_value(section, option, value, comment, default=default)
            return value
        except (ValueError, configparser.NoSectionError, configparser.NoOptionError):
            self.add_value(section, option, default, comment, default=default)
            return default

    def add_value(self, section, option, value, comment, min_val="", max_val="", default=""):
        value = str(value)
        min_val = str(min_val) if min_val else None
        max_val = str(max_val) if max_val else None
        default = str(default)
        if not self.config.has_section(section):
            self.config.add_section(section)

        if comment:
            self.config.set(section, "# " + comment.replace("\n", "\n# "))
        comment_str = "min: " + min_val + " " if min_val else ""
        comment_str += "max: " + max_val + " " if max_val else ""
        comment_str += "default: " + default + " " if default else ""
        self.config.set(section, "# " + comment_str)

        if self.config.has_option(section, option):
            self.config.remove_option(section, option)
        self.config.set(section, option, value)

    def get_float(self, section, option, min_val, max_val, default, comment=""):
        try:
            value = self.config.getfloat(section, option)
            self.add_value(section, option, value, comment, min_val, max_val, default)
            return self.get_min_max(value, min_val, max_val)
        except (ValueError, configparser.NoSectionError, configparser.NoOptionError):
            self.add_value(section, option, default, comment, min_val, max_val, default)
            return default

    def get_int(self, section, option, min_val, max_val, default, comment=""):
        try:
            value = self.config.getint(section, option)
            self.add_value(section, option, value, comment, min_val, max_val, default)
            return self.get_min_max(value, min_val, max_val)
        except (ValueError, configparser.NoSectionError, configparser.NoOptionError):
            self.add_value(section, option, default, comment, min_val, max_val, default)
            return default

    @staticmethod
    def get_min_max(value, min_val, max_val):
        if min_val and value < min_val:
            return min_val
        elif max_val and value > max_val:
            return max_val
        else:
            return value

    def save(self):
        path_parts = os.path.split(self.path)
        path = ""
        for index in range(0, len(path_parts)):
            if index < len(path_parts) - 1:
                path += os.path.sep + path_parts[index]
        if os.name == "nt":
            path = path.replace(os.path.sep, "", 1)
        path = os.path.abspath(path)
        if not os.path.exists(path):
            os.makedirs(path)
        file_out = open(self.path, "w")
        self.config.write(file_out)
        file_out.close()


================================================
FILE: src/server/data/config_general.py
================================================
from src.server.data.config import Config


class ConfigGeneral:
    scan_timeout = None
    config = Config()
    stream_audio = None
    input_delay = None
    video_quality = None
    stream_video = None

    def __init__(self):
        pass

    @classmethod
    def load(cls):
        cls.config.load("~/.drc-sim/server.conf")
        # Audio
        cls.stream_audio = cls.config.get_boolean("AUDIO", "stream", True, "Stream audio to clients")
        # Input
        cls.input_delay = cls.config.get_int("INPUT", "delay", 0, 1000, 100, "Amount of time in milliseconds to send "
                                                                             "input to the Wii U")
        # Video
        cls.video_quality = cls.config.get_int("VIDEO", "quality", 0, 100, 75, "Quality of video stream.\n"
                                                                               "5/10/15 low - 75 lan - 100 loopback\n"
                                                                               "There is latency at 100.")
        cls.stream_video = cls.config.get_boolean("VIDEO", "stream", True, "Stream video to clients")
        # General
        cls.scan_timeout = cls.config.get_int("GENERAL", "scan_timeout", 0, 60 * 5, 60 * 2, "Sets the time "
                                                                                            "allowed to scan for the "
                                                                                            "Wii U")

    @classmethod
    def save(cls):
        cls.config.save()


================================================
FILE: src/server/data/constants.py
================================================
import os

# Info
VERSION = "2.0"
NAME = "DRC SIM Server"

# Paths
PATH_ROOT = os.path.expanduser("~/.drc-sim/")
PATH_LOG_DIR = os.path.join(PATH_ROOT, "log/")
PATH_CONF_CONNECT = os.path.join(PATH_ROOT, "connect_to_wii_u.conf")
PATH_LOG_WPA = os.path.join(PATH_LOG_DIR, "wpa_supplicant_drc.log")
PATH_CONF_NETWORK_MANAGER = "/etc/NetworkManager/NetworkManager.conf"
PATH_TMP = "/tmp/drc-sim/"
PATH_CONF_CONNECT_TMP = os.path.join(PATH_TMP, "get_psk.conf")
PATH_LOG_DRC_SIM_C = os.path.join(PATH_LOG_DIR, "drc_sim_c.log")


================================================
FILE: src/server/data/resource.py
================================================
import os

import pkg_resources
import sys

from src.server.util.logging.logger import Logger


def join(*args):
    return os.path.join(*args)


class Resource:
    def __init__(self, in_path):
        pre = "resources/"
        Logger.debug("Loading resource \"%s\"", join(pre, in_path))
        current_dir = os.path.dirname(__file__).split(os.sep)
        # Check local files first
        file_path = "/"
        if len(current_dir) >= 3:
            for path in range(0, len(current_dir) - 3):
                file_path = join(file_path, current_dir[path])
            file_path = join(file_path, pre, in_path)
            if os.path.exists(file_path):
                try:
                    with open(file_path) as f:
                        self.resource = f.read()
                except UnicodeDecodeError:
                    Logger.debug("Opening resource as binary.")
                    with open(file_path, "rb") as f:
                        self.resource = f.read()
                Logger.extra("Found resource in local resource directory.")
                return
        # Check /usr/local - pip installs to here
        file_path = "/usr/local/resources/" + in_path
        if os.path.exists(file_path):
            try:
                with open(file_path) as f:
                    self.resource = f.read()
            except UnicodeDecodeError:
                Logger.debug("Opening resource as binary.")
                with open(file_path, "rb") as f:
                    self.resource = f.read()
                Logger.extra("Found resource in /usr/local/ resource directory.")
                return
        # Attempt to get from package - setup.py installs here
        try:
            self.resource = pkg_resources.resource_string(pkg_resources.Requirement.parse("drcsim"), join(pre, in_path))
            Logger.extra("Found resource in package.")
        except FileNotFoundError:
            Logger.throw("Could not find resource: %s" % join(pre, in_path))
            sys.exit()


================================================
FILE: src/server/data/struct/__init__.py
================================================


================================================
FILE: src/server/data/struct/command.py
================================================
import construct

header_cmd0 = construct.Struct(
    'magic' / construct.Int8ub,
    'unk_0' / construct.Int8ub,
    'unk_1' / construct.Int8ub,
    'unk_2' / construct.Int8ub,
    'unk_3' / construct.Int8ub,
    'flags' / construct.Int8ub,
    'id_primary' / construct.Int8ub,
    'id_secondary' / construct.Int8ub,
    'error_code' / construct.Int16ub,
    'payload_size_cmd0' / construct.Int16ub
)
header_cmd1 = construct.Struct(
    "f1" / construct.Int8ub,
    "unknown_0" / construct.Int16ub,
    "f3" / construct.Int8ub,
    "mic_enabled" / construct.Int8ub,
    "mic_mute" / construct.Int8ub,
    "mic_volume" / construct.Int16ub,
    "mic_volume_2" / construct.Int16ub,
    "unknown_a" / construct.Int8ub,
    "unknown_b" / construct.Int8ub,
    "mic_freq" / construct.Int16ub,
    "cam_enable" / construct.Int8ub,
    "cam_power" / construct.Int8ub,
    "cam_power_freq" / construct.Int8ub,
    "cam_auto_expo" / construct.Int8ub,
    "cam_expo_abs" / construct.Int32ub,
    "cam_brightness" / construct.Int16ub,
    "cam_contrast" / construct.Int16ub,
    "cam_gain" / construct.Int16ub,
    "cam_hue" / construct.Int16ub,
    "cam_saturation" / construct.Int16ub,
    "cam_sharpness" / construct.Int16ub,
    "cam_gamma" / construct.Int16ub,
    "cam_key_frame" / construct.Int8ub,
    "cam_white_balance_auto" / construct.Int8ub,
    "cam_white_balance" / construct.Int32ub,
    "cam_multiplier" / construct.Int16ub,
    "cam_multiplier_limit" / construct.Int16ub,
    construct.Padding(2)
)
header_cmd2 = construct.Struct(
    'JDN_base' / construct.Int16ul,
    construct.Padding(2),
    'seconds' / construct.Int32ul
)
header = construct.Struct(
    'packet_type' / construct.Int16ul,
    'cmd_id' / construct.Int16ul,
    'payload_size' / construct.Int16ul,
    'seq_id' / construct.Int16ul,
    construct.Embedded(
        construct.Switch(lambda ctx: ctx.cmd_id,
                         {
                             0: construct.If(
                                 lambda ctx: ctx.payload_size >= header_cmd0.sizeof(),
                                 header_cmd0),
                             1: construct.If(
                                 lambda ctx: ctx.payload_size == header_cmd1.sizeof(),
                                 header_cmd1),
                             2: construct.If(
                                 lambda ctx: ctx.payload_size == header_cmd2.sizeof(),
                                 header_cmd2)
                         },
                         default=construct.Pass
                         )
    )
)


================================================
FILE: src/server/data/struct/input.py
================================================
import construct

accelerometer_data = construct.Struct(
    "accel_x" / construct.Int16sl,
    "accel_y" / construct.Int16sl,
    "accel_z" / construct.Int16sl
)

gyroscope_data = construct.BitStruct(
    "gyro_roll" / construct.BitsInteger(24),
    "gyro_yaw" / construct.BitsInteger(24),
    "gyro_pitch" / construct.BitsInteger(24)
)

magnet_data = construct.Struct(
    construct.Padding(6)
)

touchscreen_coords_data = construct.BitStruct(
    "touch_pad" / construct.Bit,
    "touch_extra" / construct.BitsInteger(3),
    "touch_value" / construct.BitsInteger(12)
)
touchscreen_points_data = construct.Struct(
    "coords" / construct.Array(2, touchscreen_coords_data)
)
touchscreen_data = construct.Struct(
    "points" / construct.Array(10, touchscreen_points_data)
)

input_data = construct.Struct(
    "sequence_id" / construct.Int16ub,
    "buttons" / construct.Int16ub,
    "power_status" / construct.Int8ub,
    "battery_charge" / construct.Int8ub,
    "left_stick_x" / construct.Int16ub,
    "left_stick_y" / construct.Int16ub,
    "right_stick_x" / construct.Int16ub,
    "right_stick_y" / construct.Int16ub,
    "audio_volume" / construct.Int8ub,
    construct.Embedded(accelerometer_data),
    construct.Embedded(gyroscope_data),
    construct.Embedded(magnet_data),
    construct.Embedded(touchscreen_data),
    "unkown_0" / construct.BytesInteger(4),
    "extra_buttons" / construct.Int8ub,
    "unknown_1" / construct.BytesInteger(46),
    "fw_version_neg" / construct.Int8ub
)


================================================
FILE: src/server/ui/__init__.py
================================================


================================================
FILE: src/server/ui/cli/__init__.py
================================================


================================================
FILE: src/server/ui/cli/cli_main.py
================================================
import os
import time

from src.server.data import constants
from src.server.data.args import Args
from src.server.data.resource import Resource
from src.server.util.drc_sim_c import DrcSimC
from src.server.util.interface_util import InterfaceUtil
from src.server.util.logging.logger_cli import LoggerCli
from src.server.util.process_util import ProcessUtil
from src.server.util.wpa_supplicant import WpaSupplicant


class CliMain:
    def __init__(self):
        self.getting_key = False
        self.drc_sim_c = None
        self.wpa_supplicant = None

    def start(self):
        if Args.args.run_server:
            self.run_server()
        elif Args.args.get_key:
            self.get_key()
        else:
            self.stop()

    def stop(self):
        LoggerCli.info("Stopping")
        ProcessUtil.call(["killall", "dhclient"])
        self.getting_key = False
        if self.drc_sim_c:
            self.drc_sim_c.stop()
        if self.wpa_supplicant:
            self.wpa_supplicant.stop()

    def run_server(self):
        LoggerCli.info("Starting server")
        normal_interface = Args.args.normal_interface
        wii_u_interface = Args.args.wii_u_interface
        self.check_interfaces(normal_interface, wii_u_interface)
        self.prompt_unmanaged(wii_u_interface)
        self.wpa_supplicant = WpaSupplicant()
        self.wpa_supplicant.connect(constants.PATH_CONF_CONNECT, wii_u_interface)
        self.wpa_supplicant.add_status_change_listener(self.status_changed)
        InterfaceUtil.dhclient(wii_u_interface)
        InterfaceUtil.set_metric(normal_interface, 0)
        InterfaceUtil.set_metric(wii_u_interface, 1)
        self.drc_sim_c = DrcSimC()
        self.drc_sim_c.set_region(Args.args.region)
        self.drc_sim_c.add_status_change_listener(self.drc_sim_c_status_changed)
        self.drc_sim_c.start()
        while self.drc_sim_c.running:
            time.sleep(1)

    def drc_sim_c_status_changed(self, status):
        if status == DrcSimC.STOPPED:
            self.stop()

    @staticmethod
    def check_interfaces(normal_interface, wii_u_interface):
        if normal_interface == wii_u_interface:
            LoggerCli.throw(Exception("The Wii U and normal interfaces cannot be the same."))
        try:
            InterfaceUtil.get_mac(normal_interface)
            InterfaceUtil.get_mac(wii_u_interface)
        except ValueError:
            LoggerCli.throw(Exception("Invalid interface selected."))

    def status_changed(self, status):
        LoggerCli.info("Connection status changed to %s.", status)
        if status in (WpaSupplicant.TERMINATED, WpaSupplicant.NOT_FOUND, WpaSupplicant.DISCONNECTED,
                      WpaSupplicant.FAILED_START):
            self.stop()

    def status_changed_key(self, status):
        LoggerCli.info("Connection status changed to %s.", status)
        if status == WpaSupplicant.DISCONNECTED:
            LoggerCli.info("Successfully received PSK from the Wii U.")
            self.stop()
        elif status in (WpaSupplicant.TERMINATED, WpaSupplicant.NOT_FOUND, WpaSupplicant.FAILED_START):
            self.stop()

    def get_key(self):
        LoggerCli.info("Getting key")
        wii_u_interface = Args.args.wii_u_interface
        try:
            InterfaceUtil.get_mac(wii_u_interface)
        except ValueError:
            LoggerCli.throw(Exception("Invalid interface selected."))
        if len(Args.args.wps_pin) != 4:
            LoggerCli.throw(Exception("WPS PIN should be 4 digits"))
        self.prompt_unmanaged(wii_u_interface)
        self.create_temp_config_file()
        self.wpa_supplicant = WpaSupplicant()
        self.wpa_supplicant.get_psk(constants.PATH_CONF_CONNECT_TMP, wii_u_interface, Args.args.wps_pin)
        self.wpa_supplicant.add_status_change_listener(self.status_changed_key)
        self.getting_key = True
        while self.getting_key:
            time.sleep(1)

    @staticmethod
    def prompt_unmanaged(interface):
        if not InterfaceUtil.is_managed_by_network_manager(interface):
            return
        LoggerCli.info("The interface \"%s\" is managed by Network Manager. It must be set to "
                       "unmanaged to function with DRC Sim. Network manager will not be able to "
                       "use this interface after it is set to unmanaged.", interface)
        response = input("Set %s as unmanaged? (y/n)" % interface)
        LoggerCli.debug(response)
        if response in ("y", "yes", "Y", "Yes", "YES"):
            InterfaceUtil.set_unmanaged_by_network_manager(interface)
        else:
            LoggerCli.throw(Exception("Interface is managed by Network Manager."))

    @classmethod
    def create_temp_config_file(cls):
        if not os.path.exists(constants.PATH_TMP):
            os.mkdir(constants.PATH_TMP)
        tmp_conf = open(constants.PATH_CONF_CONNECT_TMP, "w")
        tmp_conf.write(Resource("config/get_psk.conf").resource)
        tmp_conf.close()


================================================
FILE: src/server/ui/gui/__init__.py
================================================


================================================
FILE: src/server/ui/gui/frame/__init__.py
================================================


================================================
FILE: src/server/ui/gui/frame/frame_about.py
================================================
from tkinter import Label

from src.server.data import constants
from src.server.ui.gui.frame.frame_tab import FrameTab


class FrameAbout(FrameTab):
    def __init__(self, master=None, **kw):
        super().__init__(master, **kw)
        self.text_name = Label(self, text=constants.NAME)
        self.text_version = Label(self, text="v" + constants.VERSION)
        self.text_license = Label(self,
                                  text="%s is free software: you can\n" % constants.NAME +
                                       "redistribute it and/or modify it under the\n"
                                       "terms of the GNU General Public License as\n"
                                       "published by the Free Software Foundation,\n"
                                       "either version 2 of the License, or\n"
                                       "(at your option) any later version."
                                  )

        self.text_name.grid(row=0, column=0)
        self.text_version.grid(row=1, column=0)
        self.text_license.grid(row=2, column=0)
        self.grid_columnconfigure(0, weight=1)

    def activate(self):
        pass

    def deactivate(self):
        pass

    def kill_other_tabs(self):
        return False


================================================
FILE: src/server/ui/gui/frame/frame_get_key.py
================================================
from tkinter import PhotoImage, Button, END, messagebox
from tkinter.ttk import Entry, Combobox, Label

from src.server.data import constants
from src.server.data.resource import Resource
from src.server.ui.cli.cli_main import CliMain
from src.server.ui.gui.frame.frame_tab import FrameTab
from src.server.util.interface_util import InterfaceUtil
from src.server.util.logging.logger_gui import LoggerGui
from src.server.util.wpa_supplicant import WpaSupplicant


class FrameGetKey(FrameTab):
    def __init__(self, master=None, **kw):
        FrameTab.__init__(self, master, **kw)
        self.wpa_supplicant = None
        self.getting_psk = False
        # Widgets
        button_size = 50
        # Spade
        self.button_spade = Button(self, width=button_size, height=button_size)
        self.button_spade.image = self.get_image("image/spade.gif", button_size, button_size)
        self.button_spade.config(image=self.button_spade.image)
        self.button_spade.number = 0
        # Heart
        self.button_heart = Button(self, width=button_size, height=button_size)
        self.button_heart.image = self.get_image("image/heart.gif", button_size, button_size)
        self.button_heart.config(image=self.button_heart.image)
        self.button_heart.number = 1
        # Diamond
        self.button_diamond = Button(self, width=button_size, height=button_size)
        self.button_diamond.image = self.get_image("image/diamond.gif", button_size, button_size)
        self.button_diamond.config(image=self.button_diamond.image)
        self.button_diamond.number = 2
        # Clover
        self.button_clover = Button(self, width=button_size, height=button_size)
        self.button_clover.image = self.get_image("image/clover.gif", button_size, button_size)
        self.button_clover.config(image=self.button_clover.image)
        self.button_clover.number = 3
        # Delete
        self.button_delete = Button(self, text="Delete")
        # Code
        self.entry_pair_code = Entry(self, state="readonly")
        # Status Message
        self.status_message = Label(self, state="readonly")
        # interface dropdown
        self.dropdown_wii_u = Combobox(self, state="readonly")
        # Events
        self.button_spade.bind("<Button-1>", self.button_clicked)
        self.button_heart.bind("<Button-1>", self.button_clicked)
        self.button_diamond.bind("<Button-1>", self.button_clicked)
        self.button_clover.bind("<Button-1>", self.button_clicked)
        self.button_delete.bind("<Button-1>", self.button_delete_clicked)
        # Grid
        self.button_spade.grid(column=0, row=0)
        self.button_heart.grid(column=1, row=0)
        self.button_diamond.grid(column=2, row=0)
        self.button_clover.grid(column=3, row=0)
        self.button_delete.grid(column=4, row=0)
        self.entry_pair_code.grid(column=0, row=1, columnspan=5)
        self.status_message.grid(column=0, row=3, columnspan=5)
        self.dropdown_wii_u.grid(column=0, row=2, columnspan=5)

    # noinspection PyUnusedLocal
    def button_delete_clicked(self, event):
        self.set_code_text(self.entry_pair_code.get()[:len(self.entry_pair_code.get()) - 1])

    def button_clicked(self, event):
        if self.getting_psk:
            messagebox.showerror("Running", "A pairing attempt is already im progress.")
            return
        number = str(event.widget.number)
        LoggerGui.debug("A suit button was clicked")  # Don't log numbers as the code can be derived from that
        code = self.entry_pair_code.get()
        code += number
        self.set_code_text(code)
        wii_u_interface = self.dropdown_wii_u.get()
        if not wii_u_interface:
            messagebox.showerror("No Interface", "An interface must be selected.")
            self.activate()
            return
        try:
            InterfaceUtil.get_mac(wii_u_interface)
        except ValueError:
            messagebox.showerror("Interface Error", "The selected Interface is no longer available.")
            self.activate()
            return
        if InterfaceUtil.is_managed_by_network_manager(wii_u_interface):
            set_unmanaged = messagebox.askokcancel(
                "Managed Interface", "This interface is managed by Network Manager. To use it with DRC Sim it needs "
                                     "to be set to unmanaged. Network Manager will not be able to control the interface"
                                     " after this.\nSet %s to unmanaged?" % wii_u_interface)
            if set_unmanaged:
                InterfaceUtil.set_unmanaged_by_network_manager(wii_u_interface)
            else:
                messagebox.showerror("Managed Interface", "Selected Wii U interface is managed by Network Manager.")
                self.activate()
                return
        if len(code) == 4:
            self.getting_psk = True
            self.set_code_text("")
            self.get_psk(code, wii_u_interface)

    def get_psk(self, code, interface):
        LoggerGui.debug("Attempting to get PSK")  # Don't log code
        CliMain.create_temp_config_file()
        self.wpa_supplicant = WpaSupplicant()
        self.wpa_supplicant.add_status_change_listener(self.wpa_status_changed)
        self.wpa_supplicant.get_psk(constants.PATH_CONF_CONNECT_TMP, interface, code)

    def wpa_status_changed(self, status):
        LoggerGui.debug("Wpa status changed to %s", status)
        if status == WpaSupplicant.NOT_FOUND:
            self.deactivate()
            self.activate()
            messagebox.showerror("Scan", "No Wii U found.")
        elif status == WpaSupplicant.TERMINATED:
            self.deactivate()
            self.activate()
            messagebox.showerror("Auth Fail", "Could not authenticate. Check the entered PIN.")
        elif status == WpaSupplicant.FAILED_START:
            self.deactivate()
            self.activate()
            messagebox.showerror("Error", "An unexpected error occurred.")
        elif status == WpaSupplicant.DISCONNECTED:
            self.deactivate()
            self.activate()
            messagebox.showerror("Auth Saved", "Successfully paired with Wii U.")
        elif status == WpaSupplicant.SCANNING:
            self.status_message["text"] = "Scanning"
        elif status == WpaSupplicant.CONNECTING:
            self.status_message["text"] = "Connecting"

    def activate(self):
        LoggerGui.debug("FrameTab activate called")
        self.getting_psk = False
        self.set_code_text("")
        if not self.wpa_supplicant or not self.wpa_supplicant.get_status():
            self.status_message["text"] = ""
        self.dropdown_wii_u["values"] = InterfaceUtil.get_wiiu_compatible_interfaces()

    def deactivate(self):
        LoggerGui.debug("FrameTab deactivate called")
        self.status_message["text"] = ""
        self.getting_psk = False
        if self.wpa_supplicant:
            self.wpa_supplicant.stop()
            self.wpa_supplicant = None

    @staticmethod
    def get_image(location, width, height):
        image = PhotoImage(data=Resource(location).resource)
        orig_width = image.width()
        orig_height = image.height()
        image = image.zoom(width, height)
        image = image.subsample(orig_width, orig_height)
        return image

    def set_code_text(self, text):
        self.entry_pair_code.config(state="normal")
        self.entry_pair_code.delete(0, END)
        self.entry_pair_code.insert(0, text)
        self.entry_pair_code.config(state="readonly")

    def kill_other_tabs(self):
        return True


================================================
FILE: src/server/ui/gui/frame/frame_log.py
================================================
import os
import subprocess
from tkinter import Button, CENTER, messagebox

from src.server.data import constants
from src.server.ui.gui.frame.frame_tab import FrameTab


class FrameLog(FrameTab):
    def __init__(self, master=None, **kw):
        super().__init__(master, **kw)
        self.button_log = Button(self, text="Open Log in Console")
        self.button_log.bind("<Button-1>", self.button_clicked)
        self.button_log.place(relx=0.5, rely=0.5, anchor=CENTER)
        self.log = None

    # noinspection PyUnusedLocal
    def button_clicked(self, event):
        tail = ["x-terminal-emulator", "-e", "tail", "-f"]
        for file in ("drcsim", "cli", "gui", "wpa", "backend", "drc_sim_c"):
            tail.append(os.path.join(constants.PATH_LOG_DIR, file + ".log"))
        self.deactivate()
        try:
            self.log = subprocess.Popen(tail, stdout=open(os.devnull, "w"), stderr=subprocess.PIPE)
        except FileNotFoundError:
            messagebox.showerror("Log Error", "Could not open log window.")

    def activate(self):
        pass

    def deactivate(self):
        pass

    def kill_other_tabs(self):
        return False


================================================
FILE: src/server/ui/gui/frame/frame_run_server.py
================================================
import os
from tkinter import messagebox
from tkinter.ttk import Label, Button, Combobox

from src.server.data import constants
from src.server.ui.gui.frame.frame_tab import FrameTab
from src.server.util.drc_sim_c import DrcSimC
from src.server.util.interface_util import InterfaceUtil
from src.server.util.logging.logger_gui import LoggerGui
from src.server.util.wpa_supplicant import WpaSupplicant


class FrameRunServer(FrameTab):
    def __init__(self, master=None, **kw):
        """
        GUI tab that handles interface and region selection and starting the server.
        :param master: root window
        :param kw: args
        """
        FrameTab.__init__(self, master, **kw)
        self.wii_u_interface = None
        self.normal_interface = None
        self.drc_sim_c = None
        self.wpa_supplicant = None
        LoggerGui.extra("Initializing FrameRunServer")
        # Create Widgets
        self.label_wpa = Label(self, text="Wii U Connection:")
        self.label_backend = Label(self, text="Server Status:")
        self.label_wpa_status = Label(self)
        self.label_backend_status = Label(self)
        self.button_start = Button(self, text="Start")
        self.button_stop = Button(self, text="Stop")
        self.label_wiiu_interface = Label(self, text="Wii U Interface")
        self.label_normal_interface = Label(self, text="Normal Interface")
        self.dropdown_wiiu_interface = Combobox(self, state="readonly")
        self.dropdown_normal_interface = Combobox(self, state="readonly")
        self.label_interface_info = Label(self)
        self.label_region = Label(self, text="Region")
        self.dropdown_region = Combobox(self, state="readonly")
        # Events
        self.button_start.bind("<Button-1>", self.start_server)
        self.button_stop.bind("<Button-1>", self.stop_server)
        # Position widgets
        self.label_wpa.grid(column=0, row=0, sticky="e")
        self.label_backend.grid(column=0, row=1, sticky="e")
        self.label_wpa_status.grid(column=1, row=0, sticky="w")
        self.label_backend_status.grid(column=1, row=1, sticky="w")
        self.label_wiiu_interface.grid(column=0, row=2)
        self.label_normal_interface.grid(column=0, row=3)
        self.dropdown_wiiu_interface.grid(column=1, row=2, columnspan=2)
        self.dropdown_normal_interface.grid(column=1, row=3, columnspan=2)
        self.label_region.grid(column=0, row=4)
        self.dropdown_region.grid(column=1, row=4, columnspan=2)
        self.button_start.grid(column=1, row=5)
        self.button_stop.grid(column=2, row=5)
        self.label_interface_info.grid(column=0, row=6, columnspan=3)
        LoggerGui.extra("Initialized FrameRunServer")

    def start_server(self, event=None):
        """
        Try to start wpa_supplicant and connect to a Wii U.
        :param event: Determines if this was a user initiated start.
        :return: None
        """
        if event:
            LoggerGui.debug("User clicked start server button")
        LoggerGui.debug("Start server called")
        if self.label_backend_status["text"] != DrcSimC.STOPPED and \
                (self.label_wpa_status["text"] not in (WpaSupplicant.DISCONNECTED, WpaSupplicant.TERMINATED)):
            messagebox.showerror("Running", "Server is already running")
            return
        if not os.path.exists(constants.PATH_CONF_CONNECT):
            messagebox.showerror("Auth Error",
                                 "No auth details found. Use the \"Get Key\" tab to pair with a Wii U.")
            self.activate()
            return
        self.normal_interface = self.dropdown_normal_interface.get()
        self.wii_u_interface = self.dropdown_wiiu_interface.get()
        if not self.normal_interface or not self.wii_u_interface:
            messagebox.showerror("Interface Error", "Two interfaces need to be selected.")
            self.activate()
            return
        if self.normal_interface == self.wii_u_interface:
            messagebox.showerror("Interface Error", "The selected normal and Wii U interfaces must be different.")
            self.activate()
            return
        try:
            InterfaceUtil.get_mac(self.normal_interface)
            InterfaceUtil.get_mac(self.wii_u_interface)
        except ValueError:
            messagebox.showerror("Interface Error", "The selected Interface is no longer available.")
            self.activate()
            return
        if InterfaceUtil.is_managed_by_network_manager(self.wii_u_interface):
            set_unmanaged = messagebox.askokcancel(
                "Managed Interface", "This interface is managed by Network Manager. To use it with DRC Sim it needs "
                                     "to be set to unmanaged. Network Manager will not be able to control the interface"
                                     " after this.\nSet %s to unmanaged?" % self.wii_u_interface)
            if set_unmanaged:
                InterfaceUtil.set_unmanaged_by_network_manager(self.wii_u_interface)
            else:
                messagebox.showerror("Managed Interface", "Selected Wii U interface is managed by Network Manager.")
                self.activate()
                return
        LoggerGui.debug("Starting wpa supplicant")
        self.wpa_supplicant = WpaSupplicant()
        self.wpa_supplicant.add_status_change_listener(self.wpa_status_changed)
        self.wpa_supplicant.connect(constants.PATH_CONF_CONNECT, self.wii_u_interface)
        self.label_backend_status.config(text="WAITING")

    def wpa_status_changed(self, status):
        """
        Handles wpa status changes. Initializes backend server if a connection is made.
        :param status: status message
        :return: None
        """
        LoggerGui.debug("Wpa changed status to %s", status)
        self.label_wpa_status.config(text=status)
        if status == WpaSupplicant.CONNECTED:
            LoggerGui.debug("Routing")
            InterfaceUtil.dhclient(self.wii_u_interface)
            InterfaceUtil.set_metric(self.normal_interface, 0)
            InterfaceUtil.set_metric(self.wii_u_interface, 1)
            LoggerGui.debug("Starting backend")
            self.drc_sim_c = DrcSimC()
            self.drc_sim_c.add_status_change_listener(self.backend_status_changed)
            self.drc_sim_c.set_region(self.dropdown_region.get())
            self.drc_sim_c.start()
            self.label_interface_info.config(text="Server IP: " + InterfaceUtil.get_ip(self.normal_interface)
                                                  + "\n" + os.uname()[1])
        elif status in (WpaSupplicant.DISCONNECTED, WpaSupplicant.TERMINATED):
            self.stop_server()
        elif status == WpaSupplicant.NOT_FOUND:
            self.stop_server()
            messagebox.showerror("Scan Error", "No Wii U found.")
        elif status == WpaSupplicant.FAILED_START:
            self.stop_server()
            messagebox.showerror("Cannot Connect", "Failed to start wpa_supplicant_drc. This could mean there is a "
                                                   "configuration error or wpa_supplicant_drc is not installed. "
                                                   "Check %s for details." % constants.PATH_LOG_WPA)

    def backend_status_changed(self, status):
        """
        Handles backend status changes.
        :param status: status message
        :return: None
        """
        LoggerGui.debug("Backend status changed to %s", status)
        self.label_backend_status.config(text=status)
        if status == DrcSimC.STOPPED:
            self.stop_server()

    def stop_server(self, event=None):
        """
        Stops active threads.
        :param event: Determines if this is a user initiated stop
        :return: None
        """
        if event:
            LoggerGui.debug("User clicked stop server button")
        LoggerGui.debug("Stop server called")
        if event and (self.label_wpa_status["text"] in (WpaSupplicant.DISCONNECTED, WpaSupplicant.TERMINATED)
                      and self.label_backend_status["text"] == DrcSimC.STOPPED):
            messagebox.showerror("Stop", "Server is not running.")
            return
        if self.drc_sim_c:
            self.drc_sim_c.stop()
            self.drc_sim_c = None
        if self.wpa_supplicant:
            self.wpa_supplicant.stop()
            self.wpa_supplicant = None
        self.activate()

    def activate(self):
        """
        Initializes the frame.
        :return: None
        """
        LoggerGui.debug("FrameRunServer activated")
        self.dropdown_wiiu_interface["values"] = InterfaceUtil.get_wiiu_compatible_interfaces()
        self.dropdown_normal_interface["values"] = InterfaceUtil.get_all_interfaces()
        self.dropdown_region["values"] = ["NONE", "NA"]
        self.label_wpa_status["text"] = self.wpa_supplicant.get_status() \
            if self.wpa_supplicant and self.wpa_supplicant.get_status() else WpaSupplicant.DISCONNECTED
        self.label_backend_status["text"] = self.drc_sim_c.get_status() \
            if self.drc_sim_c and self.drc_sim_c.get_status() else DrcSimC.STOPPED
        self.button_start.config(state="normal")
        self.button_stop.config(state="normal")
        self.label_interface_info.config(text="")

    def deactivate(self):
        """
        De-initializes the frame.
        :return: None
        """
        LoggerGui.debug("FrameRunServer deactivated")
        self.stop_server()

    def kill_other_tabs(self):
        return True


================================================
FILE: src/server/ui/gui/frame/frame_tab.py
================================================
from tkinter.ttk import Frame


class FrameTab(Frame):
    def __init__(self, master=None, **kw):
        Frame.__init__(self, master, **kw)

    def activate(self):
        raise NotImplementedError()

    def deactivate(self):
        raise NotImplementedError()

    def kill_other_tabs(self):
        raise NotImplementedError()


================================================
FILE: src/server/ui/gui/gui_main.py
================================================
import tkinter
from tkinter.ttk import Notebook

from src.server.data.resource import Resource
from src.server.ui.gui.frame.frame_about import FrameAbout
from src.server.ui.gui.frame.frame_get_key import FrameGetKey
from src.server.ui.gui.frame.frame_log import FrameLog
from src.server.ui.gui.frame.frame_run_server import FrameRunServer
from src.server.util.logging.logger_gui import LoggerGui


class GuiMain:
    def __init__(self):
        """
        Main Gui Entrance
        """
        tkinter.Tk.report_callback_exception = self.throw
        # Main window
        self.destroyed = False
        LoggerGui.info("Initializing GUI")
        self.main_window = tkinter.Tk()
        self.main_window.wm_title("DRC Sim Server")
        icon = tkinter.PhotoImage(data=Resource("image/icon.gif").resource)
        self.main_window.tk.call("wm", "iconphoto", self.main_window, icon)
        self.main_window.protocol("WM_DELETE_WINDOW", self.on_closing)
        self.main_window.resizable(False, False)
        # Notebook
        self.tab_id = None
        self.notebook = Notebook(self.main_window, width=300, height=150)
        self.notebook.grid(column=0, row=0)
        self.notebook.bind("<<NotebookTabChanged>>", self.on_tab_changed)
        # Run Server Frame
        self.frame_run_server = FrameRunServer(self.notebook)
        self.notebook.add(self.frame_run_server, text="Run Server")
        # Get Key Frame
        self.frame_get_key = FrameGetKey(self.notebook)
        self.notebook.add(self.frame_get_key, text="Get Key")
        # Log Frame
        self.frame_log = FrameLog(self.notebook)
        self.notebook.add(self.frame_log, text="Log")
        # About Frame
        self.frame_about = FrameAbout(self.notebook)
        self.notebook.add(self.frame_about, text="About")

    @staticmethod
    def throw(*args):
        """
        Throw exceptions from Tkinter
        :param args: arguments
        :return: None
        """
        for arg in args:
            if isinstance(arg, Exception):
                LoggerGui.throw(arg)

    def after(self):
        """
        Empty loop to catch KeyboardInterrupt
        :return: None
        """
        self.main_window.after(1000, self.after)

    def start(self):
        """
        Start the main window loop
        :return: 
        """
        LoggerGui.info("Opening GUI")
        self.after()
        self.main_window.mainloop()
        LoggerGui.info("GUI Closed")

    def stop(self):
        """
        Convenience function to call on_closing()
        :return: None
        """
        self.on_closing()

    def on_closing(self):
        """
        Close the main window and current tab
        :return: None
        """
        if self.destroyed:
            return
        self.destroyed = True
        LoggerGui.info("Closing GUI")
        if self.tab_id in self.notebook.children:
            self.notebook.children[self.tab_id].deactivate()
        try:
            self.main_window.destroy()
        except Exception as e:
            LoggerGui.exception(e)

    # noinspection PyUnusedLocal
    def on_tab_changed(self, event):
        """
        Close the previous tab and initialize a new one
        :param event: tab event
        :return: None
        """
        tab_id = self.notebook.select()
        tab_index = self.notebook.index(tab_id)
        tab_name = self.notebook.tab(tab_index, "text")
        LoggerGui.debug("Notebook tab changed to \"%s\" with id %d", tab_name, tab_index)
        self.tab_id = tab_id.split(".")[len(tab_id.split(".")) - 1]  # Parse notebook/tab id to only tab id
        if self.notebook.children[self.tab_id].kill_other_tabs():
            for tab in self.notebook.children:
                if tab != self.tab_id:
                    self.notebook.children[tab].deactivate()
        self.notebook.children[self.tab_id].activate()


================================================
FILE: src/server/util/__init__.py
================================================


================================================
FILE: src/server/util/drc_sim_c.py
================================================
import subprocess
from threading import Thread

import time

from src.server.data import constants
from src.server.data.args import Args
from src.server.data.config_general import ConfigGeneral
from src.server.util.logging.logger_backend import LoggerBackend
from src.server.util.process_util import ProcessUtil
from src.server.util.status_sending_thread import StatusSendingThread


class DrcSimC(StatusSendingThread):
    UNKNOWN = "UNKNOWN"
    STOPPED = "STOPPED"
    RUNNING = "RUNNING"

    def __init__(self):
        """
        Helper for interacting with drc_sim_c.
        """
        super().__init__()
        self.running = False
        self.status = self.UNKNOWN
        self.drc_sim_c_process = None
        self.status_check_thread = None
        self.region = "none"

    def set_region(self, region):
        self.region = region

    def start(self):
        if Args.args.disable_server:
            return
        self.running = True
        self.kill_drc_sim_c()
        LoggerBackend.debug("Starting drc_sim_c")
        command = ["drc_sim_c", "-region", self.region, "-video-quality", str(ConfigGeneral.video_quality),
                   "-input-delay", str(ConfigGeneral.input_delay)]
        if not ConfigGeneral.stream_video:
            command.append("--no-video")
        if not ConfigGeneral.stream_audio:
            command.append("--no-audio")
        if Args.args.debug:
            command.append("-d")
        if Args.args.extra:
            command.append("-e")
        if Args.args.finer:
            command.append("-f")
        if Args.args.verbose:
            command.append("-v")
        self.drc_sim_c_process = subprocess.Popen(command, stdout=open(constants.PATH_LOG_DRC_SIM_C, "w"),
                                                  stderr=subprocess.STDOUT)
        LoggerBackend.debug("Starting status check thread")
        self.status_check_thread = Thread(target=self.check_status, name="drc_sim_c Status Check Thread")
        self.status_check_thread.start()
        self.set_status(self.RUNNING)

    def check_status(self):
        while self.running:
            if self.drc_sim_c_process.poll():
                self.set_status(self.STOPPED)
            time.sleep(1)

    def stop(self):
        """
        Stops any background thread that is running
        :return: None
        """
        self.running = False
        LoggerBackend.debug("Stopping drc_sim_c")
        if self.drc_sim_c_process and self.drc_sim_c_process.poll() is None:
            self.drc_sim_c_process.terminate()
            self.kill_drc_sim_c()
        # reset
        self.clear_status_change_listeners()
        LoggerBackend.debug("Stopped drc_sim_c")

    @staticmethod
    def kill_drc_sim_c():
        ProcessUtil.call(["killall", "drc_sim_c"])


================================================
FILE: src/server/util/interface_util.py
================================================
import netifaces
import os

from src.server.data import constants
from src.server.util.logging.logger import Logger
from src.server.util.os_util import OsUtil
from src.server.util.process_util import ProcessUtil


class InterfaceUtil:
    def __init__(self):
        pass

    @classmethod
    def get_wiiu_compatible_interfaces(cls):
        """
        Returns a list of interfaces that can operate on the 5GHz spectrum
        :return: array of interface names
        """
        all_interfaces = cls.get_all_interfaces()
        compatible_interfaces = []
        for interface in all_interfaces:
            if cls.is_interface_wiiu_compatible(interface):
                compatible_interfaces.append(interface)
        return compatible_interfaces

    @classmethod
    def get_all_interfaces(cls):
        """
        Gets a list of all system network interfaces
        :return: array of interface names
        """
        interfaces = []
        for interface in netifaces.interfaces():
            interfaces.append(interface)
        return interfaces

    @classmethod
    def is_interface_wiiu_compatible(cls, interface):
        if not OsUtil.is_linux():
            Logger.extra("Ignoring interface compatibility check for %s", interface)
            return False
        frequency_info = ProcessUtil.get_output(["iwlist", interface, "frequency"])
        return "5." in frequency_info
        # TODO check for 802.11n compliance

    @classmethod
    def get_ip(cls, interface):
        addresses = netifaces.ifaddresses(interface)
        if netifaces.AF_INET in addresses:
            return addresses[netifaces.AF_INET][0]["addr"]
        return ""

    @classmethod
    def get_mac(cls, interface):
        addresses = netifaces.ifaddresses(interface)
        if netifaces.AF_LINK in addresses:
            return addresses[netifaces.AF_LINK][0]["addr"]
        return "0"

    @classmethod
    def set_metric(cls, interface, metric):
        ProcessUtil.call(["ifmetric", interface, str(metric)])

    @classmethod
    def dhclient(cls, interface):
        ProcessUtil.call(["killall", "dhclient"])
        ProcessUtil.call(["dhclient", interface])

    @classmethod
    def is_managed_by_network_manager(cls, interface):
        if not os.path.exists(constants.PATH_CONF_NETWORK_MANAGER):
            Logger.debug("Network manager config not found.")
            return False
        conf = open(constants.PATH_CONF_NETWORK_MANAGER)
        conf_data = conf.readlines()
        conf.close()
        managed = False
        for line in conf_data:
            if line.startswith("unmanaged-devices=") and "mac:" + cls.get_mac(interface) not in line:
                managed = True  # Ensure configs with duplicates raise an unmanaged prompt
        if "unmanaged-devices=" not in " ".join(conf_data):
            managed = True
        Logger.debug("Interface \"%s\" managed by network manager: %s", interface, managed)
        return managed

    @classmethod
    def set_unmanaged_by_network_manager(cls, interface):
        Logger.debug("Adding interface \"%s-%s\" as an unmanaged interface to network manager", interface,
                     cls.get_mac(interface))
        with open(constants.PATH_CONF_NETWORK_MANAGER, "r") as conf_read:
            conf = conf_read.read().splitlines()
        added = False
        entry = "mac:" + cls.get_mac(interface)
        # Add Entry
        for line in range(0, len(conf)):
            # Add keyfile plugin if it's not enabled
            if conf[line].startswith("plugins=") and "keyfile" not in conf[line]:
                conf[line] += ",keyfile"
            # Add unmanaged device
            if conf[line].startswith("unmanaged-devices=") and entry not in conf[line]:
                conf[line] += ";" + entry
                added = True
        # Add the initial unmanaged entry if it was not present
        if not added:
            conf.append("[keyfile]")
            conf.append("unmanaged-devices=" + entry)
        # Write
        with open(constants.PATH_CONF_NETWORK_MANAGER, "w") as conf_write:
            for line in conf:
                conf_write.write(line + "\n")
        # Restart the service
        ProcessUtil.call(["service", "network-manager", "restart"])
        ProcessUtil.call(["service", "networking", "restart"])


================================================
FILE: src/server/util/logging/__init__.py
================================================


================================================
FILE: src/server/util/logging/logger.py
================================================
import logging
import os
import shutil

from src.server.data import constants
from src.server.util.os_util import OsUtil


class Logger:
    level = logging.INFO
    INFO = logging.INFO
    DEBUG = logging.DEBUG
    EXTRA = logging.DEBUG - 1
    FINER = logging.DEBUG - 2
    VERBOSE = logging.DEBUG - 3
    logger = logging.getLogger("drcsim")
    console_handler = None
    file_handler = None

    def __init__(self, name=None):
        if not Logger.console_handler or not Logger.file_handler:
            Logger.logger, Logger.console_handler, Logger.file_handler = self.create_logger(name)
        # Level names
        logging.addLevelName(Logger.EXTRA, "EXTRA")
        logging.addLevelName(Logger.FINER, "FINER")
        logging.addLevelName(Logger.VERBOSE, "VERBOSE")

    @classmethod
    def info(cls, message, *args):
        cls.logger.info(message, *args)

    @classmethod
    def debug(cls, message, *args):
        cls.logger.debug(message, *args)

    @classmethod
    def extra(cls, message, *args):
        cls.logger.log(cls.EXTRA, message, *args)

    @classmethod
    def verbose(cls, message, *args):
        cls.logger.log(cls.VERBOSE, message, *args)

    @classmethod
    def set_level(cls, level):
        cls.level = level
        cls.logger.setLevel(cls.level)
        cls.console_handler.setLevel(cls.level)
        cls.file_handler.setLevel(cls.level)

    @classmethod
    def warn(cls, message, *args):
        cls.logger.warning(message, *args)

    @classmethod
    def throw(cls, exception, message=None, *args):
        cls.logger.error(str("=" * 10 + " [ CRASH ] " + "=" * 10))
        OsUtil.log_info(cls.logger)
        if message:
            cls.logger.error(message, *args)
        if isinstance(exception, Exception):
            cls.logger.exception(exception)
        else:
            cls.logger.error(exception)
        cls.logger.error(str("=" * 10 + " [ CRASH ] " + "=" * 10))
        if cls != Logger:
            raise exception

    @classmethod
    def finer(cls, message, *args):
        cls.logger.log(cls.FINER, message, *args)

    @classmethod
    def exception(cls, exception, *args):
        cls.logger.log(cls.EXTRA, exception, *args, exc_info=1)

    @classmethod
    def get_level(cls):
        return cls.level

    @staticmethod
    def create_logger(name):
        logger = logging.getLogger(name)
        format_str = "%(asctime)s %(levelname)s:%(name)s %(message)s"
        # Console output
        console_handler = logging.StreamHandler()
        console_handler.setFormatter(logging.Formatter(format_str))
        logger.addHandler(console_handler)
        # File output
        log_path = os.path.join(constants.PATH_LOG_DIR, logger.name + ".log")
        if not os.path.exists(constants.PATH_ROOT):
            os.mkdir(constants.PATH_ROOT)
        if not os.path.exists(constants.PATH_LOG_DIR):
            os.mkdir(constants.PATH_LOG_DIR)
        if os.path.exists(log_path):
            shutil.copyfile(log_path, log_path.replace(".log", "-1.log"))
            os.remove(log_path)
        file_handler = logging.FileHandler(log_path)
        file_handler.setFormatter(logging.Formatter(format_str))
        logger.addHandler(file_handler)
        return logger, console_handler, file_handler

Logger("drcsim")


================================================
FILE: src/server/util/logging/logger_backend.py
================================================
from src.server.util.logging.logger import Logger


class LoggerBackend(Logger):
    def __init__(self, name=None):
        Logger.__init__(self, name)
        LoggerBackend.logger, LoggerBackend.console_handler, LoggerBackend.file_handler = self.create_logger(name)


LoggerBackend("backend")


================================================
FILE: src/server/util/logging/logger_cli.py
================================================
from src.server.util.logging.logger import Logger


class LoggerCli(Logger):
    def __init__(self, name=None):
        Logger.__init__(self, name)
        LoggerCli.logger, LoggerCli.console_handler, LoggerCli.file_handler = self.create_logger(name)

LoggerCli("cli")


================================================
FILE: src/server/util/logging/logger_gui.py
================================================
from src.server.util.logging.logger import Logger


class LoggerGui(Logger):
    def __init__(self, name=None):
        Logger.__init__(self, name)
        LoggerGui.logger, LoggerGui.console_handler, LoggerGui.file_handler = self.create_logger(name)

LoggerGui("gui")


================================================
FILE: src/server/util/logging/logger_wpa.py
================================================
from src.server.util.logging.logger import Logger


class LoggerWpa(Logger):
    def __init__(self, name=None):
        Logger.__init__(self, name)
        LoggerWpa.logger, LoggerWpa.console_handler, LoggerWpa.file_handler = self.create_logger(name)

LoggerWpa("wpa")


================================================
FILE: src/server/util/os_util.py
================================================
import os
import platform as _platform


class OsUtil:
    platform = os.name
    name = _platform.system()
    release = _platform.release()
    distro = _platform.linux_distribution()

    def __init__(self):
        pass

    @classmethod
    def is_windows(cls):
        return "windows" in cls.name.lower()

    @classmethod
    def log_info(cls, logger):
        if not cls.is_linux():
            logger.warn("This OS is not supported")
        # Log info
        logger.debug("OS platform: %s", cls.platform)
        logger.debug("OS name: %s", cls.name)
        if cls.is_linux():
            logger.debug("OS distro: %s", cls.distro)
        logger.debug("OS release: %s", cls.release)

    @classmethod
    def is_linux(cls):
        return "linux" in cls.name.lower()


================================================
FILE: src/server/util/process_util.py
================================================
import subprocess

import errno

from src.server.util.logging.logger import Logger


class ProcessUtil:
    def __init__(self):
        pass

    @classmethod
    def get_output(cls, command, silent=False):
        """
        Wraps a subprocess.check_output call. Checks for process errors and command not found errors.
        :param silent: If silent is true the command will not be logged
        :param command: array of strings - same as check_output
        :return: string of output, error, or None if the command is not found
        """
        try:
            if not silent:
                Logger.extra("Attempting to execute command %s", command)
            output = subprocess.check_output(command, stderr=subprocess.STDOUT, universal_newlines=True)
        except OSError as e:
            output = ""
            if e.errno == errno.ENOENT:
                Logger.warn("\"%s\" may not be installed", command[0])
            else:
                Logger.exception(e)
            cls.log_failed_command(command)
        except subprocess.CalledProcessError as e:
            output = e.output
            cls.log_failed_command(command, output.strip())
        Logger.verbose("Command \"%s\" output %s", command, output)
        return output

    @classmethod
    def call(cls, command):
        """
        Same as subprocess.call but outputs to logger
        :param command: string array - same as call
        :return: None
        """
        cls.get_output(command)

    @classmethod
    def log_failed_command(cls, command, output=None):
        Logger.extra("Failed to execute command \"%s\" and got output \"%s\"", command, output)


================================================
FILE: src/server/util/status_sending_thread.py
================================================
class StatusSendingThread:
    def __init__(self):
        """
        Helper for registering callback status.
        """
        self.status_change_listeners = []
        self.status = None

    def set_status(self, status):
        """
        Set and notify callbacks if the status does not match the current status.
        :param status: status message
        :return: None
        """
        if self.status != status:
            self.status = status
            for listener in self.status_change_listeners:
                listener(status)

    def get_status(self):
        """
        Status getter
        :return: status string
        """
        return self.status

    def add_status_change_listener(self, callback):
        """
        Add a callback that will be called on status change.
        :param callback: callable function
        :return: None
        """
        self.status_change_listeners.append(callback)

    def clear_status_change_listeners(self):
        """
        Cleat the status callbacks.
        :return: None
        """
        self.status_change_listeners = []


================================================
FILE: src/server/util/wpa_supplicant.py
================================================
import re
import subprocess
import time
from threading import Thread

import pexpect

from src.server.data import constants
from src.server.data.config_general import ConfigGeneral
from src.server.util.logging.logger_wpa import LoggerWpa
from src.server.util.process_util import ProcessUtil
from src.server.util.status_sending_thread import StatusSendingThread


class WpaSupplicant(StatusSendingThread):
    UNKNOWN = "UNKNOWN"
    CONNECTING = "CONNECTING"
    CONNECTED = "CONNECTED"
    TERMINATED = "TERMINATED"
    DISCONNECTED = "DISCONNECTED"
    SCANNING = "SCANNING"
    NOT_FOUND = "NOT_FOUND"
    FAILED_START = "FAILED_START"

    def __init__(self):
        """
        Helper for interacting with wpa_supplicant_drc and wpa_cli_drc.
        """
        super().__init__()
        self.time_scan = 0
        self.time_start = 0
        self.mac_addr_regex = re.compile('^([0-9A-Fa-f]{2}[:-]){5}([0-9A-Fa-f]{2})')
        self.wiiu_ap_regex = re.compile('^([0-9A-Fa-f]{2}[:-]){5}([0-9A-Fa-f]{2})(\s*\d*\s*-*\d*\s*)'
                                        '(\[WPA2-PSK-CCMP\])?'
                                        '(\[ESS\])(\s*)(WiiU|\\\\x00)(.+)$')  # \x00 is escaped (\\x00)
        self.running = False
        self.status = self.UNKNOWN
        self.status_check_thread = None
        self.wpa_supplicant_process = None
        self.psk_thread = None
        self.psk_thread_cli = None

    def connect(self, conf_path, interface, status_check=True):
        """
        Starts a thread that connects to the Wii U.
        Status:
          FAILED_START: wpa_supplicant_drc did not initialize
          SCANNING: wpa_supplicant_drc is scanning
          CONNECTED: wpa_supplicant_drc is connected to an AP
          CONNECTING: wpa_supplicant_drc is authenticating
          TERMINATED: wpa_supplicant_drc was found by the T-1000 Cyberdyne Systems Model 101
          NOT_FOUND: wpa_supplicant_drc could not find a Wii U AP
          UNKNOWN: wpa_supplicant_drc is in a state that is unhandled - it will be logged
        :return: None
        """
        LoggerWpa.debug("Connect called")
        self.running = True
        self.unblock_wlan()
        self.kill_wpa()
        command = ["wpa_supplicant_drc", "-Dnl80211", "-i", interface, "-c", conf_path]
        if LoggerWpa.get_level() == LoggerWpa.FINER:
            command.append("-d")
        elif LoggerWpa.get_level() == LoggerWpa.VERBOSE:
            command.append("-dd")
        LoggerWpa.debug("Starting wpa supplicant")
        self.wpa_supplicant_process = subprocess.Popen(command, stdout=open(constants.PATH_LOG_WPA, "w"),
                                                       stderr=subprocess.STDOUT)
        LoggerWpa.debug("Started wpa supplicant")
        if status_check:
            LoggerWpa.debug("Starting status check thread")
            self.status_check_thread = Thread(target=self.check_status, name="WPA Status Check Thread")
            self.status_check_thread.start()

    def check_status(self):
        """
        Thread that checks WPA status every second
        Updates 
        :return: None
        """
        while self.running:
            wpa_status = self.wpa_cli("status")
            scan_results = self.wpa_cli("scan_results")
            not_started_message = "Failed to connect to non-global ctrl_ifname"
            LoggerWpa.finer("Scan Results: %s", scan_results)
            LoggerWpa.finer("Status: %s", wpa_status)
            # process is dead or wpa_supplicant has not started
            if self.wpa_supplicant_process.poll() or not_started_message in scan_results:
                LoggerWpa.finer("%d seconds until start timeout", 30 - self.time_start)
                # wait for wpa_supplicant to initialize
                if self.time_start >= 5:
                    status = self.FAILED_START
                else:
                    status = self.status
                    self.time_start += 1
            # scanning
            elif not self.scan_contains_wii_u(scan_results) or "wpa_state=SCANNING" in wpa_status:
                LoggerWpa.finer("%d seconds until scan timeout", ConfigGeneral.scan_timeout - self.time_scan)
                # disconnect
                if self.time_scan == -1:
                    status = self.DISCONNECTED
                # timeout scan
                elif self.time_scan >= ConfigGeneral.scan_timeout:
                    status = self.NOT_FOUND
                else:
                    status = self.SCANNING
                    self.time_scan += 1
            elif "wpa_state=COMPLETED" in wpa_status:
                status = self.CONNECTED
                self.time_scan = -1  # forces a disconnect - might need to be handled better
            elif "wpa_state=AUTHENTICATING" in wpa_status or "wpa_state=ASSOCIATING" in wpa_status:
                status = self.CONNECTING
            elif "wpa_state=DISCONNECTED" in wpa_status:
                status = self.DISCONNECTED
                if self.time_scan != -1:
                    status = self.FAILED_START
            else:
                LoggerWpa.extra("WPA status: %s", wpa_status)
                status = self.UNKNOWN
            self.set_status(status)
            time.sleep(1)

    @staticmethod
    def kill_wpa():
        """
        Makes a system call to kill wpa_supplicant_drc
        :return: None
        """
        ProcessUtil.call(["killall", "wpa_supplicant_drc"])

    @staticmethod
    def unblock_wlan():
        """
        Make a system call to unblock wlan
        :return: None
        """
        ProcessUtil.call(["rfkill", "unblock", "wlan"])

    @staticmethod
    def wpa_cli(command):
        """
        Makes a system call to wpa_cli_drc
        :param command: command to pass to wpa_cli_drc
        :return: command output
        """
        if isinstance(command, str):
            command = [command]
        return ProcessUtil.get_output(["wpa_cli_drc", "-p", "/var/run/wpa_supplicant_drc"] + command, silent=True)

    def stop(self):
        """
        Stops any background thread that is running
        :return: None
        """
        if not self.running:
            LoggerWpa.debug("Ignored stop request: already stopped")
            return
        self.running = False
        if self.psk_thread_cli and self.psk_thread_cli.isalive():
            LoggerWpa.debug("Stopping psk pexpect spawn")
            self.psk_thread_cli.sendline("quit")
            self.psk_thread_cli.close(True)
        LoggerWpa.debug("Stopping wpa process")
        if self.wpa_supplicant_process and self.wpa_supplicant_process.poll() is None:
            self.wpa_supplicant_process.terminate()
            self.kill_wpa()
        # reset
        self.clear_status_change_listeners()
        self.time_start = 0
        self.time_scan = 0
        LoggerWpa.debug("Wpa stopped")

    def scan_contains_wii_u(self, scan_results):
        """
        Check if string contains Wii U SSID
        :param scan_results: string
        :return: boolean
        """
        for line in scan_results.splitlines():
            if self.wiiu_ap_regex.match(line):
                return True
        return False

    def scan_is_empty(self, scan_results):
        """
        Check if the scan has no MAC addresses
        :param scan_results: string
        :return: boolean
        """
        for line in scan_results.split("\n"):
            if self.mac_addr_regex.match(line):
                return False
        return True

    def get_psk(self, conf_path, interface, code):
        """
        Starts a thread to connect and attempt to obtain a Wii U's PSK
        Status:
          FAILED_START: there was an error attempting to parse CLI output - exception is logged
          NOT_FOUND: wpa_supplicant_drc did not find any Wii U APs
          TERMINATED: wpa_supplicant_drc could not authenticate with any SSIDs
          DISCONNECTED: auth details were saved
          SCANNING: scan has started
          CONNECTING: attempting to authenticate with a Wii U
        :return: None
        """
        self.connect(conf_path, interface, status_check=False)
        self.psk_thread = Thread(target=self.get_psk_thread, kwargs={"code": code}, name="PSK Thread")
        self.psk_thread.start()

    def get_psk_thread(self, code):
        """
        Thread that attempts to authenticate with a Wii U. Updates status
        :param code: WPS PIN
        :return: None
        """
        try:
            LoggerWpa.debug("CLI expect starting")
            self.psk_thread_cli = pexpect.spawn("wpa_cli_drc -p /var/run/wpa_supplicant_drc")
            LoggerWpa.debug("CLI expect Waiting for init")
            self.psk_thread_cli.expect("Interactive mode")
            # Scan for Wii U SSIDs
            scan_tries = 5
            wii_u_bssids = []
            self.set_status(self.SCANNING)
            while self.running and scan_tries > 0:
                self.psk_thread_cli.sendline("scan")
                LoggerWpa.debug("CLI expect waiting for scan results available event")
                scan_wait_tries = 60
                while self.running:
                    try:
                        self.psk_thread_cli.expect("<3>CTRL-EVENT-SCAN-RESULTS", timeout=1)
                        break
                    except pexpect.TIMEOUT:
                        scan_wait_tries -= 1
                        if scan_wait_tries <= 0:
                            raise pexpect.TIMEOUT("Scan timeout")
                self.psk_thread_cli.sendline("scan_results")
                LoggerWpa.debug("CLI expect waiting for scan results")
                self.psk_thread_cli.expect("bssid / frequency / signal level / flags / ssid")
                for line in range(0, 100):  # up to 100 APs
                    try:
                        self.psk_thread_cli.expect(self.mac_addr_regex.pattern, timeout=1)
                    except pexpect.TIMEOUT:
                        break
                scan_results = self.psk_thread_cli.before.decode()
                LoggerWpa.finer("CLI expect - scan results: %s", scan_results)
                for line in scan_results.splitlines():
                    if self.wiiu_ap_regex.match(line):
                        wii_u_bssids.append(line.split()[0])
                if len(wii_u_bssids) == 0:
                    scan_tries -= 1
                else:
                    scan_tries = 0
            # Check for found Wii U ssids
            if len(wii_u_bssids) == 0:
                LoggerWpa.debug("No Wii U SSIDs found")
                self.set_status(self.NOT_FOUND)
                return
            # attempt to pair with any wii u bssid
            self.set_status(self.CONNECTING)
            for bssid in wii_u_bssids:
                self.psk_thread_cli.sendline("wps_pin %s %s" % (bssid, code + "5678"))
                LoggerWpa.debug("CLI expect waiting for wps_pin input confirmation")
                self.psk_thread_cli.expect(code + "5678")
                LoggerWpa.debug("CLI expect waiting for authentication")
                try:
                    connect_wait_tries = 60
                    while self.running:
                        try:
                            self.psk_thread_cli.expect("<3>WPS-CRED-RECEIVED", timeout=1)
                            break
                        except pexpect.TIMEOUT:
                            connect_wait_tries -= 1
                            if connect_wait_tries <= 0:
                                raise pexpect.TIMEOUT("Connect Timeout")
                    # save conf
                    LoggerWpa.debug("PSK obtained")
                    # Save to temp config before reading from it
                    self.psk_thread_cli.sendline("save_config")
                    self.psk_thread_cli.expect("OK", timeout=5)
                    self.save_connect_conf(bssid)
                    self.set_status(self.DISCONNECTED)
                    return
                except pexpect.TIMEOUT:
                    LoggerWpa.debug("CLI expect BSSID auth failed")
                    self.psk_thread_cli.sendline("reconnect")
                    self.psk_thread_cli.expect("OK")
        # Timed out
        except pexpect.TIMEOUT as e:
            LoggerWpa.debug("PSK get attempt ended with an error.")
            LoggerWpa.exception(e)
            self.set_status(self.FAILED_START)
        # Unexpected EOF
        except pexpect.EOF as e:
            if self.running:  # Thread was not killed
                LoggerWpa.exception(e)
            return
        # Failed to authenticate
        LoggerWpa.debug("Could not authenticate with any SSIDs")
        self.set_status(self.TERMINATED)

    @staticmethod
    def save_connect_conf(bssid):
        """
        Modify the temp get_psk configuration to be a connect configurraton and save it to
         ~/.drc-sim/connect_to_wii_u.conf.
        :param bssid: Wii U BSSID
        :return: None
        """
        LoggerWpa.debug("Saving connection config")
        # add additional connect information to config
        conf = open(constants.PATH_CONF_CONNECT_TMP, "r")
        lines = conf.readlines()
        conf.close()
        for line in lines:
            if "update_config=1" in line:
                lines.insert(lines.index(line) + 1, "ap_scan=1\n")
                break
        for line in lines:
            if "network={" in line:
                lines.insert(lines.index(line) + 1, "\tscan_ssid=1\n")
                lines.insert(lines.index(line) + 2, "\tbssid=" + bssid + "\n")
                break
        save_conf = open(constants.PATH_CONF_CONNECT, "w")
        save_conf.writelines(lines)
        save_conf.close()
        LoggerWpa.info("Authenticated with the Wii U")


================================================
FILE: tests/packets/.gitignore
================================================
!*.bin

================================================
FILE: tests/test_parse.py
================================================
import os


def test_video_parse():
    """
    Reads dumped video packets and sends them to the video handler
    :return: None
    """
    '''ConfigServer.load()
    handler = VideoHandler()
    with open(os.path.join(os.path.dirname(__file__), "packets/video.bin"), "rb") as video_packets:
        read = True
        while read:
            packet = b""
            while b"|\n" not in packet:
                read_byte = video_packets.read(1)
                if not read_byte:
                    return
                packet += read_byte
            packet = packet.replace(b"|\n", b"")
            handler.update(packet, True)'''
    pass
Download .txt
gitextract_j_pnps2_/

├── .gitignore
├── .travis.yml
├── Dockerfile
├── MANIFEST.in
├── drc-info.py
├── drc-sim-backend
├── install.sh
├── license.txt
├── readme.md
├── resources/
│   ├── bin/
│   │   └── drcsimbackend.desktop
│   └── config/
│       └── get_psk.conf
├── setup.py
├── src/
│   ├── __init__.py
│   └── server/
│       ├── __init__.py
│       ├── data/
│       │   ├── __init__.py
│       │   ├── args.py
│       │   ├── config.py
│       │   ├── config_general.py
│       │   ├── constants.py
│       │   ├── resource.py
│       │   └── struct/
│       │       ├── __init__.py
│       │       ├── command.py
│       │       └── input.py
│       ├── ui/
│       │   ├── __init__.py
│       │   ├── cli/
│       │   │   ├── __init__.py
│       │   │   └── cli_main.py
│       │   └── gui/
│       │       ├── __init__.py
│       │       ├── frame/
│       │       │   ├── __init__.py
│       │       │   ├── frame_about.py
│       │       │   ├── frame_get_key.py
│       │       │   ├── frame_log.py
│       │       │   ├── frame_run_server.py
│       │       │   └── frame_tab.py
│       │       └── gui_main.py
│       └── util/
│           ├── __init__.py
│           ├── drc_sim_c.py
│           ├── interface_util.py
│           ├── logging/
│           │   ├── __init__.py
│           │   ├── logger.py
│           │   ├── logger_backend.py
│           │   ├── logger_cli.py
│           │   ├── logger_gui.py
│           │   └── logger_wpa.py
│           ├── os_util.py
│           ├── process_util.py
│           ├── status_sending_thread.py
│           └── wpa_supplicant.py
└── tests/
    ├── packets/
    │   └── .gitignore
    └── test_parse.py
Download .txt
SYMBOL INDEX (152 symbols across 25 files)

FILE: drc-info.py
  function print_packet (line 31) | def print_packet(sock, name):
  function print_packet_cmd (line 36) | def print_packet_cmd(sock):
  function send_cmd (line 57) | def send_cmd(data):
  function send_command_from_string (line 61) | def send_command_from_string(command_string, sid):
  function cmd_request (line 74) | def cmd_request():
  function print_hid (line 103) | def print_hid(sock):

FILE: setup.py
  class CompileDrcSimC (line 10) | class CompileDrcSimC(Command):
  class CompileWpaSupplicantDrc (line 14) | class CompileWpaSupplicantDrc(Command):

FILE: src/server/data/args.py
  class Args (line 8) | class Args:
    method __init__ (line 11) | def __init__(self):
    method parse_args (line 15) | def parse_args():

FILE: src/server/data/config.py
  class Config (line 5) | class Config:
    method __init__ (line 7) | def __init__(self):
    method load (line 11) | def load(self, path):
    method get_boolean (line 15) | def get_boolean(self, section, option, default, comment=""):
    method add_value (line 24) | def add_value(self, section, option, value, comment, min_val="", max_v...
    method get_float (line 43) | def get_float(self, section, option, min_val, max_val, default, commen...
    method get_int (line 52) | def get_int(self, section, option, min_val, max_val, default, comment=...
    method get_min_max (line 62) | def get_min_max(value, min_val, max_val):
    method save (line 70) | def save(self):

FILE: src/server/data/config_general.py
  class ConfigGeneral (line 4) | class ConfigGeneral:
    method __init__ (line 12) | def __init__(self):
    method load (line 16) | def load(cls):
    method save (line 34) | def save(cls):

FILE: src/server/data/resource.py
  function join (line 9) | def join(*args):
  class Resource (line 13) | class Resource:
    method __init__ (line 14) | def __init__(self, in_path):

FILE: src/server/ui/cli/cli_main.py
  class CliMain (line 14) | class CliMain:
    method __init__ (line 15) | def __init__(self):
    method start (line 20) | def start(self):
    method stop (line 28) | def stop(self):
    method run_server (line 37) | def run_server(self):
    method drc_sim_c_status_changed (line 56) | def drc_sim_c_status_changed(self, status):
    method check_interfaces (line 61) | def check_interfaces(normal_interface, wii_u_interface):
    method status_changed (line 70) | def status_changed(self, status):
    method status_changed_key (line 76) | def status_changed_key(self, status):
    method get_key (line 84) | def get_key(self):
    method prompt_unmanaged (line 103) | def prompt_unmanaged(interface):
    method create_temp_config_file (line 117) | def create_temp_config_file(cls):

FILE: src/server/ui/gui/frame/frame_about.py
  class FrameAbout (line 7) | class FrameAbout(FrameTab):
    method __init__ (line 8) | def __init__(self, master=None, **kw):
    method activate (line 26) | def activate(self):
    method deactivate (line 29) | def deactivate(self):
    method kill_other_tabs (line 32) | def kill_other_tabs(self):

FILE: src/server/ui/gui/frame/frame_get_key.py
  class FrameGetKey (line 13) | class FrameGetKey(FrameTab):
    method __init__ (line 14) | def __init__(self, master=None, **kw):
    method button_delete_clicked (line 65) | def button_delete_clicked(self, event):
    method button_clicked (line 68) | def button_clicked(self, event):
    method get_psk (line 104) | def get_psk(self, code, interface):
    method wpa_status_changed (line 111) | def wpa_status_changed(self, status):
    method activate (line 134) | def activate(self):
    method deactivate (line 142) | def deactivate(self):
    method get_image (line 151) | def get_image(location, width, height):
    method set_code_text (line 159) | def set_code_text(self, text):
    method kill_other_tabs (line 165) | def kill_other_tabs(self):

FILE: src/server/ui/gui/frame/frame_log.py
  class FrameLog (line 9) | class FrameLog(FrameTab):
    method __init__ (line 10) | def __init__(self, master=None, **kw):
    method button_clicked (line 18) | def button_clicked(self, event):
    method activate (line 28) | def activate(self):
    method deactivate (line 31) | def deactivate(self):
    method kill_other_tabs (line 34) | def kill_other_tabs(self):

FILE: src/server/ui/gui/frame/frame_run_server.py
  class FrameRunServer (line 13) | class FrameRunServer(FrameTab):
    method __init__ (line 14) | def __init__(self, master=None, **kw):
    method start_server (line 59) | def start_server(self, event=None):
    method wpa_status_changed (line 111) | def wpa_status_changed(self, status):
    method backend_status_changed (line 142) | def backend_status_changed(self, status):
    method stop_server (line 153) | def stop_server(self, event=None):
    method activate (line 174) | def activate(self):
    method deactivate (line 191) | def deactivate(self):
    method kill_other_tabs (line 199) | def kill_other_tabs(self):

FILE: src/server/ui/gui/frame/frame_tab.py
  class FrameTab (line 4) | class FrameTab(Frame):
    method __init__ (line 5) | def __init__(self, master=None, **kw):
    method activate (line 8) | def activate(self):
    method deactivate (line 11) | def deactivate(self):
    method kill_other_tabs (line 14) | def kill_other_tabs(self):

FILE: src/server/ui/gui/gui_main.py
  class GuiMain (line 12) | class GuiMain:
    method __init__ (line 13) | def __init__(self):
    method throw (line 46) | def throw(*args):
    method after (line 56) | def after(self):
    method start (line 63) | def start(self):
    method stop (line 73) | def stop(self):
    method on_closing (line 80) | def on_closing(self):
    method on_tab_changed (line 97) | def on_tab_changed(self, event):

FILE: src/server/util/drc_sim_c.py
  class DrcSimC (line 14) | class DrcSimC(StatusSendingThread):
    method __init__ (line 19) | def __init__(self):
    method set_region (line 30) | def set_region(self, region):
    method start (line 33) | def start(self):
    method check_status (line 60) | def check_status(self):
    method stop (line 66) | def stop(self):
    method kill_drc_sim_c (line 81) | def kill_drc_sim_c():

FILE: src/server/util/interface_util.py
  class InterfaceUtil (line 10) | class InterfaceUtil:
    method __init__ (line 11) | def __init__(self):
    method get_wiiu_compatible_interfaces (line 15) | def get_wiiu_compatible_interfaces(cls):
    method get_all_interfaces (line 28) | def get_all_interfaces(cls):
    method is_interface_wiiu_compatible (line 39) | def is_interface_wiiu_compatible(cls, interface):
    method get_ip (line 48) | def get_ip(cls, interface):
    method get_mac (line 55) | def get_mac(cls, interface):
    method set_metric (line 62) | def set_metric(cls, interface, metric):
    method dhclient (line 66) | def dhclient(cls, interface):
    method is_managed_by_network_manager (line 71) | def is_managed_by_network_manager(cls, interface):
    method set_unmanaged_by_network_manager (line 88) | def set_unmanaged_by_network_manager(cls, interface):

FILE: src/server/util/logging/logger.py
  class Logger (line 9) | class Logger:
    method __init__ (line 20) | def __init__(self, name=None):
    method info (line 29) | def info(cls, message, *args):
    method debug (line 33) | def debug(cls, message, *args):
    method extra (line 37) | def extra(cls, message, *args):
    method verbose (line 41) | def verbose(cls, message, *args):
    method set_level (line 45) | def set_level(cls, level):
    method warn (line 52) | def warn(cls, message, *args):
    method throw (line 56) | def throw(cls, exception, message=None, *args):
    method finer (line 70) | def finer(cls, message, *args):
    method exception (line 74) | def exception(cls, exception, *args):
    method get_level (line 78) | def get_level(cls):
    method create_logger (line 82) | def create_logger(name):

FILE: src/server/util/logging/logger_backend.py
  class LoggerBackend (line 4) | class LoggerBackend(Logger):
    method __init__ (line 5) | def __init__(self, name=None):

FILE: src/server/util/logging/logger_cli.py
  class LoggerCli (line 4) | class LoggerCli(Logger):
    method __init__ (line 5) | def __init__(self, name=None):

FILE: src/server/util/logging/logger_gui.py
  class LoggerGui (line 4) | class LoggerGui(Logger):
    method __init__ (line 5) | def __init__(self, name=None):

FILE: src/server/util/logging/logger_wpa.py
  class LoggerWpa (line 4) | class LoggerWpa(Logger):
    method __init__ (line 5) | def __init__(self, name=None):

FILE: src/server/util/os_util.py
  class OsUtil (line 5) | class OsUtil:
    method __init__ (line 11) | def __init__(self):
    method is_windows (line 15) | def is_windows(cls):
    method log_info (line 19) | def log_info(cls, logger):
    method is_linux (line 30) | def is_linux(cls):

FILE: src/server/util/process_util.py
  class ProcessUtil (line 8) | class ProcessUtil:
    method __init__ (line 9) | def __init__(self):
    method get_output (line 13) | def get_output(cls, command, silent=False):
    method call (line 38) | def call(cls, command):
    method log_failed_command (line 47) | def log_failed_command(cls, command, output=None):

FILE: src/server/util/status_sending_thread.py
  class StatusSendingThread (line 1) | class StatusSendingThread:
    method __init__ (line 2) | def __init__(self):
    method set_status (line 9) | def set_status(self, status):
    method get_status (line 20) | def get_status(self):
    method add_status_change_listener (line 27) | def add_status_change_listener(self, callback):
    method clear_status_change_listeners (line 35) | def clear_status_change_listeners(self):

FILE: src/server/util/wpa_supplicant.py
  class WpaSupplicant (line 15) | class WpaSupplicant(StatusSendingThread):
    method __init__ (line 25) | def __init__(self):
    method connect (line 43) | def connect(self, conf_path, interface, status_check=True):
    method check_status (line 74) | def check_status(self):
    method kill_wpa (line 123) | def kill_wpa():
    method unblock_wlan (line 131) | def unblock_wlan():
    method wpa_cli (line 139) | def wpa_cli(command):
    method stop (line 149) | def stop(self):
    method scan_contains_wii_u (line 172) | def scan_contains_wii_u(self, scan_results):
    method scan_is_empty (line 183) | def scan_is_empty(self, scan_results):
    method get_psk (line 194) | def get_psk(self, conf_path, interface, code):
    method get_psk_thread (line 210) | def get_psk_thread(self, code):
    method save_connect_conf (line 303) | def save_connect_conf(bssid):

FILE: tests/test_parse.py
  function test_video_parse (line 4) | def test_video_parse():
Condensed preview — 49 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (121K chars).
[
  {
    "path": ".gitignore",
    "chars": 115,
    "preview": "__pycache__/\n*.pyc\n.idea/\n.pypy/\nbuild/\ndist/\n*.egg-info/\nsetup.cfg\ntemp/\n.drc-sim/\nregion_dump.json\n*.bin\n.cache/\n"
  },
  {
    "path": ".travis.yml",
    "chars": 206,
    "preview": "language: python\npython:\n  - \"3.4\"\n  - \"3.5\"\n  - \"3.6\"\ndist: trusty\nsudo: required\ninstall:\n  - sudo apt-get -qq update\n"
  },
  {
    "path": "Dockerfile",
    "chars": 298,
    "preview": "FROM debian:jessie\n\nADD drc-sim-backend /root/\nADD setup.py /root/\nADD src/ /root/src/\nADD resources/ /root/resources/\nA"
  },
  {
    "path": "MANIFEST.in",
    "chars": 23,
    "preview": "recursive-include src *"
  },
  {
    "path": "drc-info.py",
    "chars": 5215,
    "preview": "import codecs\nimport json\nimport select\nimport socket\nimport sys\nimport time\nfrom threading import Thread\n\nfrom src.serv"
  },
  {
    "path": "drc-sim-backend",
    "chars": 2894,
    "preview": "#!/usr/bin/env python3\nimport os\nimport sys\n\nfrom src.server.data import constants\nfrom src.server.data.args import Args"
  },
  {
    "path": "install.sh",
    "chars": 10891,
    "preview": "#!/usr/bin/env bash\n# drc-sim(-backend): Wii U gamepad emulator.\n#\n# drc-sim-backend install script\n# https://github.com"
  },
  {
    "path": "license.txt",
    "chars": 18813,
    "preview": "Copyright (C) 2017 Rolando Islas\n\nThis file is part of DRC Sim Server.\n\nDRC Sim Server is free software: you can redistr"
  },
  {
    "path": "readme.md",
    "chars": 1590,
    "preview": "DRC Sim Server\n---\n\nStable: [![Build Status](https://travis-ci.org/rolandoislas/drc-sim.svg?branch=master)](https://trav"
  },
  {
    "path": "resources/bin/drcsimbackend.desktop",
    "chars": 210,
    "preview": "[Desktop Entry]\nVersion=1.0\nName=DRC SIM Server\nComment=Wii U Gamepad Emulator Backend Server\nExec=gksu /usr/local/bin/d"
  },
  {
    "path": "resources/config/get_psk.conf",
    "chars": 59,
    "preview": "ctrl_interface=/var/run/wpa_supplicant_drc\nupdate_config=1\n"
  },
  {
    "path": "setup.py",
    "chars": 1313,
    "preview": "#!/usr/bin/env python3\n\nfrom distutils.core import setup, Command\n\nfrom setuptools import find_packages\n\nfrom src.server"
  },
  {
    "path": "src/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "src/server/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "src/server/data/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "src/server/data/args.py",
    "chars": 2414,
    "preview": "import argparse\n\nimport sys\n\nfrom src.server.data import constants\n\n\nclass Args:\n    args = None\n\n    def __init__(self)"
  },
  {
    "path": "src/server/data/config.py",
    "chars": 3321,
    "preview": "import configparser\nimport os\n\n\nclass Config:\n\n    def __init__(self):\n        self.path = \"\"\n        self.config = conf"
  },
  {
    "path": "src/server/data/config_general.py",
    "chars": 1546,
    "preview": "from src.server.data.config import Config\n\n\nclass ConfigGeneral:\n    scan_timeout = None\n    config = Config()\n    strea"
  },
  {
    "path": "src/server/data/constants.py",
    "chars": 522,
    "preview": "import os\n\n# Info\nVERSION = \"2.0\"\nNAME = \"DRC SIM Server\"\n\n# Paths\nPATH_ROOT = os.path.expanduser(\"~/.drc-sim/\")\nPATH_LO"
  },
  {
    "path": "src/server/data/resource.py",
    "chars": 2015,
    "preview": "import os\n\nimport pkg_resources\nimport sys\n\nfrom src.server.util.logging.logger import Logger\n\n\ndef join(*args):\n    ret"
  },
  {
    "path": "src/server/data/struct/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "src/server/data/struct/command.py",
    "chars": 2560,
    "preview": "import construct\n\nheader_cmd0 = construct.Struct(\n    'magic' / construct.Int8ub,\n    'unk_0' / construct.Int8ub,\n    'u"
  },
  {
    "path": "src/server/data/struct/input.py",
    "chars": 1499,
    "preview": "import construct\n\naccelerometer_data = construct.Struct(\n    \"accel_x\" / construct.Int16sl,\n    \"accel_y\" / construct.In"
  },
  {
    "path": "src/server/ui/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "src/server/ui/cli/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "src/server/ui/cli/cli_main.py",
    "chars": 4968,
    "preview": "import os\nimport time\n\nfrom src.server.data import constants\nfrom src.server.data.args import Args\nfrom src.server.data."
  },
  {
    "path": "src/server/ui/gui/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "src/server/ui/gui/frame/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "src/server/ui/gui/frame/frame_about.py",
    "chars": 1261,
    "preview": "from tkinter import Label\n\nfrom src.server.data import constants\nfrom src.server.ui.gui.frame.frame_tab import FrameTab\n"
  },
  {
    "path": "src/server/ui/gui/frame/frame_get_key.py",
    "chars": 7592,
    "preview": "from tkinter import PhotoImage, Button, END, messagebox\nfrom tkinter.ttk import Entry, Combobox, Label\n\nfrom src.server."
  },
  {
    "path": "src/server/ui/gui/frame/frame_log.py",
    "chars": 1163,
    "preview": "import os\nimport subprocess\nfrom tkinter import Button, CENTER, messagebox\n\nfrom src.server.data import constants\nfrom s"
  },
  {
    "path": "src/server/ui/gui/frame/frame_run_server.py",
    "chars": 9545,
    "preview": "import os\nfrom tkinter import messagebox\nfrom tkinter.ttk import Label, Button, Combobox\n\nfrom src.server.data import co"
  },
  {
    "path": "src/server/ui/gui/frame/frame_tab.py",
    "chars": 333,
    "preview": "from tkinter.ttk import Frame\n\n\nclass FrameTab(Frame):\n    def __init__(self, master=None, **kw):\n        Frame.__init__"
  },
  {
    "path": "src/server/ui/gui/gui_main.py",
    "chars": 3873,
    "preview": "import tkinter\nfrom tkinter.ttk import Notebook\n\nfrom src.server.data.resource import Resource\nfrom src.server.ui.gui.fr"
  },
  {
    "path": "src/server/util/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "src/server/util/drc_sim_c.py",
    "chars": 2790,
    "preview": "import subprocess\nfrom threading import Thread\n\nimport time\n\nfrom src.server.data import constants\nfrom src.server.data."
  },
  {
    "path": "src/server/util/interface_util.py",
    "chars": 4322,
    "preview": "import netifaces\nimport os\n\nfrom src.server.data import constants\nfrom src.server.util.logging.logger import Logger\nfrom"
  },
  {
    "path": "src/server/util/logging/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "src/server/util/logging/logger.py",
    "chars": 3289,
    "preview": "import logging\nimport os\nimport shutil\n\nfrom src.server.data import constants\nfrom src.server.util.os_util import OsUtil"
  },
  {
    "path": "src/server/util/logging/logger_backend.py",
    "chars": 294,
    "preview": "from src.server.util.logging.logger import Logger\n\n\nclass LoggerBackend(Logger):\n    def __init__(self, name=None):\n    "
  },
  {
    "path": "src/server/util/logging/logger_cli.py",
    "chars": 269,
    "preview": "from src.server.util.logging.logger import Logger\n\n\nclass LoggerCli(Logger):\n    def __init__(self, name=None):\n        "
  },
  {
    "path": "src/server/util/logging/logger_gui.py",
    "chars": 269,
    "preview": "from src.server.util.logging.logger import Logger\n\n\nclass LoggerGui(Logger):\n    def __init__(self, name=None):\n        "
  },
  {
    "path": "src/server/util/logging/logger_wpa.py",
    "chars": 269,
    "preview": "from src.server.util.logging.logger import Logger\n\n\nclass LoggerWpa(Logger):\n    def __init__(self, name=None):\n        "
  },
  {
    "path": "src/server/util/os_util.py",
    "chars": 780,
    "preview": "import os\nimport platform as _platform\n\n\nclass OsUtil:\n    platform = os.name\n    name = _platform.system()\n    release "
  },
  {
    "path": "src/server/util/process_util.py",
    "chars": 1658,
    "preview": "import subprocess\n\nimport errno\n\nfrom src.server.util.logging.logger import Logger\n\n\nclass ProcessUtil:\n    def __init__"
  },
  {
    "path": "src/server/util/status_sending_thread.py",
    "chars": 1109,
    "preview": "class StatusSendingThread:\n    def __init__(self):\n        \"\"\"\n        Helper for registering callback status.\n        \""
  },
  {
    "path": "src/server/util/wpa_supplicant.py",
    "chars": 13746,
    "preview": "import re\nimport subprocess\nimport time\nfrom threading import Thread\n\nimport pexpect\n\nfrom src.server.data import consta"
  },
  {
    "path": "tests/packets/.gitignore",
    "chars": 6,
    "preview": "!*.bin"
  },
  {
    "path": "tests/test_parse.py",
    "chars": 647,
    "preview": "import os\n\n\ndef test_video_parse():\n    \"\"\"\n    Reads dumped video packets and sends them to the video handler\n    :retu"
  }
]

About this extraction

This page contains the full source code of the rolandoislas/drc-sim GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 49 files (111.0 KB), approximately 27.4k tokens, and a symbol index with 152 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!