<commit_before>#include "Game.hpp"

#include "SystemInfo/SystemInfo.hpp"

namespace swift
{
	Game::Game(const std::string& t, unsigned tps)
		:	running(false),
			title(t),
			console(500, 200, defaultFont, "$:"),
			graphics(Quality::Medium),
			smoothing(true),
			fullscreen(false),
			verticalSync(true),
			resolution({800, 600}),
			soundLevel(100),
			musicLevel(75),
			ticksPerSecond(tps)
	{
	}

	Game::~Game()
	{
		if(currentState)
			delete currentState;
	}

	// Do any pre-game data loading
	// Such as setting up the scripting virtual machine
	// and setting game quality settings.
	// That's about it
	void Game::start(int c, char** args)
	{
		// c is the total arguments
		// args is the arguments

		// loads settings from the settings file
		loadSettings("./data/settings/settings.ini");

		handleLaunchOps(c, args);

		// Window set up.
		if(fullscreen)
			window.create(sf::VideoMode::getDesktopMode(), title, sf::Style::Fullscreen);
		else
			window.create({resolution.x, resolution.y, 32}, title, sf::Style::Titlebar | sf::Style::Close);

		// get System Info
		log	<< "OS:\t\t" << getOSName() << '\n'
			<< "Version:\t" << getOSVersion() << '\n'
			<< "Arch:\t\t" << getOSArch() << '\n'
			<< "Total Mem:\t" << getTotalMem() << '\n'
			<< "CPU:\t\t" << getCPUModel() << '\n'
			<< "Video Vendor:\t" << getVideoVendor() << '\n'
			<< "Video Card:\t" << getVideoCard() << '\n'
			<< "Video Driver:\t" << getVideoDriver() << "\n\n";

		//window.setIcon(SwiftEngineIcon.width, SwiftEngineIcon.height, SwiftEngineIcon.pixel_data);
		window.setVerticalSyncEnabled(verticalSync);
		window.setKeyRepeatEnabled(false);

		assets.setSmooth(smoothing);
		assets.loadResourceFolder("./data/animations");
		assets.loadResourceFolder("./data/textures");
		assets.loadResourceFolder("./data/fonts");
		assets.loadResourceFolder("./data/music");
		assets.loadResourceFolder("./data/scripts");
		assets.loadResourceFolder("./data/skeletons");
		assets.loadResourceFolder("./data/sounds");

		log << '\n';

		mods.loadMods("./data/mods");

		for(auto &m : mods.getMods())
		{
			assets.loadMod(m.second.mod);
		}

		defaultFont = assets.getFont("./data/fonts/segoeuisl.ttf");

		running = true;

		// fps display
		if(debug)
		{
			FPS.setFont(defaultFont);
			FPS.setScale(0.7, 0.7);
			FPS.setString("000.000");
			FPS.setColor(sf::Color::White);
			FPS.setPosition(window.getSize().x - (FPS.getGlobalBounds().width + 10), 10);
		}

		// setup Script static variables
		Script::setWindow(window);
		Script::setAssetManager(assets);
		Script::setClock(GameTime);
		Script::setSettings(settings);

		// state setup
		currentState = new MainMenu(window, assets);
		currentState->setup();
	}

	void Game::gameLoop()
	{
		const sf::Time dt = sf::seconds(1.f / ticksPerSecond);

		sf::Time currentTime = GameTime.getElapsedTime();
		sf::Time lag = sf::seconds(0);

		while(running)
		{
			sf::Time newTime = GameTime.getElapsedTime();
			sf::Time frameTime = newTime - currentTime;

			if(frameTime > sf::seconds(0.25))
				frameTime = sf::seconds(0.25);

			currentTime = newTime;

			lag += frameTime;

			while(lag >= dt)
			{
				update(dt);
				lag -= dt;
			}

			draw(lag.asSeconds() / dt.asSeconds());

			// frames per second measurement
			if(debug)
				FPS.setString(std::to_string(1 / frameTime.asSeconds()).substr(0, 7));
		}
	}

	// Finish cleaning up memory, close cleanly, etc
	void Game::finish()
	{
		window.close();
	}

	void Game::update(sf::Time dt)
	{
		if(running)
		{
			manageStates();
		}

		sf::Event event;
		while(window.pollEvent(event))
		{
			keyboard(event);
			mouse(event);

			// avoid having the console type the key that toggles it
			if(event.type == sf::Event::TextEntered && event.text.unicode != '\\')
				console.update(event);

			if(event.type == sf::Event::Closed)
				running = false;

			currentState->handleEvent(event);
		}

		if(running)
		{
			currentState->update(dt);
		}
	}

	void Game::manageStates()
	{
		if(currentState->switchFrom())
		{
			State::Type nextState = currentState->finish();
			delete currentState;
			currentState = nullptr;

			switch(nextState)
			{
				case State::Type::MainMenu:
					currentState = new MainMenu(window, assets);
					break;
				case State::Type::SettingsMenu:
					currentState = new SettingsMenu(window, assets, settings);
					break;
				case State::Type::Play:
					currentState = new Play(window, assets);
					break;
				case State::Type::Exit:
					running = false;
					break;
				default:
					log << "[ERROR]: State machine error, state not valid\n";
					running = false;
					break;
			}

			if(running)
				currentState->setup();
		}
	}

	void Game::draw(float e)
	{
		if(running)
		{
			/* clear display */
			window.clear();

			/* state drawing */
			currentState->draw(e);

			/* other drawing */
			window.draw(console);

			if(debug)
				window.draw(FPS);

			/* display drawing */
			window.display();
		}
	}

	void Game::addKeyboardCommands()
	{
		// add some default keybindings
		keyboard.newBinding("toggleTerminal", sf::Keyboard::BackSlash, [&]()
		{
			console.activate(!console.isActivated());
		});
	}

	void Game::addConsoleCommands()
	{
		// add some console commands
		console.addCommand("hello", [&](ArgVec /*args*/)
		{
			console << "\nHello to you too!";
			return 0;
		});

		console.addCommand("fps", [&](ArgVec /*args*/)
		{
			console << "\n" << FPS.getString();
			return 0;
		});

		console.addCommand("exit", [&](ArgVec /*args*/)
		{
			running = false;
			return 0;
		});
	}

	void Game::handleLaunchOps(int c, char** args)
	{
		// launch options
		editor = false;
		debug = false;
		fullscreen = false;

		// loop through options
		int arg = 1;	// we skip arg 0 because arg 0 is the executable
		while(arg < c)
		{
			if(args[arg] == std::string("editor"))
			{
				editor = true;
			}
			else if(args[arg] == std::string("debug"))
			{
				debug = true;
			}
			else if(args[arg] == std::string("fullscreen"))
			{
				fullscreen = true;
			}
			else if(args[arg] == std::string("res"))
			{
				resolution.x = std::stoi(args[arg + 1]);
				resolution.y = std::stoi(args[arg + 2]);
				arg += 2;
			}
			else if(args[arg] == std::string("videoModes"))
			{
				log << "Supported Fullscreen Video Modes:\n";

				std::vector<sf::VideoMode> modes = sf::VideoMode::getFullscreenModes();
				for(std::size_t i = 0; i < modes.size(); ++i)
				{
					sf::VideoMode mode = modes[i];
					log << "Mode #" << i << ": " << mode.width << "x" << mode.height << " - " << mode.bitsPerPixel << " bpp\n";
					// ex: "Mode #0: 1920x1080 - 32 bbp"
				}
				log << '\n';
			}
			else
			{
				log << "\nUnknown launch option: " << args[arg] << '\n';
			}

			arg++;
		}
	}

	void Game::loadSettings(const std::string& file)
	{
		// settings file settings
		if(!settings.loadFile(file))
			log << "Could not open settings file, default settings will be used\n";

		settings.get("fullscreen", fullscreen);
		settings.get("vsync", verticalSync);
		settings.get("res.x", resolution.x);
		settings.get("res.y", resolution.y);
		settings.get("sound", soundLevel);
		settings.get("music", musicLevel);
	}
}
<commit_msg>Fixed a misplaced & for a reference variable.<commit_after>#include "Game.hpp"

#include "SystemInfo/SystemInfo.hpp"

namespace swift
{
	Game::Game(const std::string& t, unsigned tps)
		:	running(false),
			title(t),
			console(500, 200, defaultFont, "$:"),
			graphics(Quality::Medium),
			smoothing(true),
			fullscreen(false),
			verticalSync(true),
			resolution({800, 600}),
			soundLevel(100),
			musicLevel(75),
			ticksPerSecond(tps)
	{
	}

	Game::~Game()
	{
		if(currentState)
			delete currentState;
	}

	// Do any pre-game data loading
	// Such as setting up the scripting virtual machine
	// and setting game quality settings.
	// That's about it
	void Game::start(int c, char** args)
	{
		// c is the total arguments
		// args is the arguments

		// loads settings from the settings file
		loadSettings("./data/settings/settings.ini");

		handleLaunchOps(c, args);

		// Window set up.
		if(fullscreen)
			window.create(sf::VideoMode::getDesktopMode(), title, sf::Style::Fullscreen);
		else
			window.create({resolution.x, resolution.y, 32}, title, sf::Style::Titlebar | sf::Style::Close);

		// get System Info
		log	<< "OS:\t\t" << getOSName() << '\n'
			<< "Version:\t" << getOSVersion() << '\n'
			<< "Arch:\t\t" << getOSArch() << '\n'
			<< "Total Mem:\t" << getTotalMem() << '\n'
			<< "CPU:\t\t" << getCPUModel() << '\n'
			<< "Video Vendor:\t" << getVideoVendor() << '\n'
			<< "Video Card:\t" << getVideoCard() << '\n'
			<< "Video Driver:\t" << getVideoDriver() << "\n\n";

		//window.setIcon(SwiftEngineIcon.width, SwiftEngineIcon.height, SwiftEngineIcon.pixel_data);
		window.setVerticalSyncEnabled(verticalSync);
		window.setKeyRepeatEnabled(false);

		assets.setSmooth(smoothing);
		assets.loadResourceFolder("./data/animations");
		assets.loadResourceFolder("./data/textures");
		assets.loadResourceFolder("./data/fonts");
		assets.loadResourceFolder("./data/music");
		assets.loadResourceFolder("./data/scripts");
		assets.loadResourceFolder("./data/skeletons");
		assets.loadResourceFolder("./data/sounds");

		log << '\n';

		mods.loadMods("./data/mods");

		for(auto& m : mods.getMods())
		{
			assets.loadMod(m.second.mod);
		}

		defaultFont = assets.getFont("./data/fonts/segoeuisl.ttf");

		running = true;

		// fps display
		if(debug)
		{
			FPS.setFont(defaultFont);
			FPS.setScale(0.7, 0.7);
			FPS.setString("000.000");
			FPS.setColor(sf::Color::White);
			FPS.setPosition(window.getSize().x - (FPS.getGlobalBounds().width + 10), 10);
		}

		// setup Script static variables
		Script::setWindow(window);
		Script::setAssetManager(assets);
		Script::setClock(GameTime);
		Script::setSettings(settings);

		// state setup
		currentState = new MainMenu(window, assets);
		currentState->setup();
	}

	void Game::gameLoop()
	{
		const sf::Time dt = sf::seconds(1.f / ticksPerSecond);

		sf::Time currentTime = GameTime.getElapsedTime();
		sf::Time lag = sf::seconds(0);

		while(running)
		{
			sf::Time newTime = GameTime.getElapsedTime();
			sf::Time frameTime = newTime - currentTime;

			if(frameTime > sf::seconds(0.25))
				frameTime = sf::seconds(0.25);

			currentTime = newTime;

			lag += frameTime;

			while(lag >= dt)
			{
				update(dt);
				lag -= dt;
			}

			draw(lag.asSeconds() / dt.asSeconds());

			// frames per second measurement
			if(debug)
				FPS.setString(std::to_string(1 / frameTime.asSeconds()).substr(0, 7));
		}
	}

	// Finish cleaning up memory, close cleanly, etc
	void Game::finish()
	{
		window.close();
	}

	void Game::update(sf::Time dt)
	{
		if(running)
		{
			manageStates();
		}

		sf::Event event;
		while(window.pollEvent(event))
		{
			keyboard(event);
			mouse(event);

			// avoid having the console type the key that toggles it
			if(event.type == sf::Event::TextEntered && event.text.unicode != '\\')
				console.update(event);

			if(event.type == sf::Event::Closed)
				running = false;

			currentState->handleEvent(event);
		}

		if(running)
		{
			currentState->update(dt);
		}
	}

	void Game::manageStates()
	{
		if(currentState->switchFrom())
		{
			State::Type nextState = currentState->finish();
			delete currentState;
			currentState = nullptr;

			switch(nextState)
			{
				case State::Type::MainMenu:
					currentState = new MainMenu(window, assets);
					break;
				case State::Type::SettingsMenu:
					currentState = new SettingsMenu(window, assets, settings);
					break;
				case State::Type::Play:
					currentState = new Play(window, assets);
					break;
				case State::Type::Exit:
					running = false;
					break;
				default:
					log << "[ERROR]: State machine error, state not valid\n";
					running = false;
					break;
			}

			if(running)
				currentState->setup();
		}
	}

	void Game::draw(float e)
	{
		if(running)
		{
			/* clear display */
			window.clear();

			/* state drawing */
			currentState->draw(e);

			/* other drawing */
			window.draw(console);

			if(debug)
				window.draw(FPS);

			/* display drawing */
			window.display();
		}
	}

	void Game::addKeyboardCommands()
	{
		// add some default keybindings
		keyboard.newBinding("toggleTerminal", sf::Keyboard::BackSlash, [&]()
		{
			console.activate(!console.isActivated());
		});
	}

	void Game::addConsoleCommands()
	{
		// add some console commands
		console.addCommand("hello", [&](ArgVec /*args*/)
		{
			console << "\nHello to you too!";
			return 0;
		});

		console.addCommand("fps", [&](ArgVec /*args*/)
		{
			console << "\n" << FPS.getString();
			return 0;
		});

		console.addCommand("exit", [&](ArgVec /*args*/)
		{
			running = false;
			return 0;
		});
	}

	void Game::handleLaunchOps(int c, char** args)
	{
		// launch options
		editor = false;
		debug = false;
		fullscreen = false;

		// loop through options
		int arg = 1;	// we skip arg 0 because arg 0 is the executable
		while(arg < c)
		{
			if(args[arg] == std::string("editor"))
			{
				editor = true;
			}
			else if(args[arg] == std::string("debug"))
			{
				debug = true;
			}
			else if(args[arg] == std::string("fullscreen"))
			{
				fullscreen = true;
			}
			else if(args[arg] == std::string("res"))
			{
				resolution.x = std::stoi(args[arg + 1]);
				resolution.y = std::stoi(args[arg + 2]);
				arg += 2;
			}
			else if(args[arg] == std::string("videoModes"))
			{
				log << "Supported Fullscreen Video Modes:\n";

				std::vector<sf::VideoMode> modes = sf::VideoMode::getFullscreenModes();
				for(std::size_t i = 0; i < modes.size(); ++i)
				{
					sf::VideoMode mode = modes[i];
					log << "Mode #" << i << ": " << mode.width << "x" << mode.height << " - " << mode.bitsPerPixel << " bpp\n";
					// ex: "Mode #0: 1920x1080 - 32 bbp"
				}
				log << '\n';
			}
			else
			{
				log << "\nUnknown launch option: " << args[arg] << '\n';
			}

			arg++;
		}
	}

	void Game::loadSettings(const std::string& file)
	{
		// settings file settings
		if(!settings.loadFile(file))
			log << "Could not open settings file, default settings will be used\n";

		settings.get("fullscreen", fullscreen);
		settings.get("vsync", verticalSync);
		settings.get("res.x", resolution.x);
		settings.get("res.y", resolution.y);
		settings.get("sound", soundLevel);
		settings.get("music", musicLevel);
	}
}
<|endoftext|>


<commit_before>//
// Created by dar on 11/27/15.
//

#include "Game.h"

Game::Game(Core *core) : core(core), renderer(core) {
}

void Game::run() {
    this->renderer.init();
    SDL_StartTextInput();
    double deltaTime = timer.GetDelta();
    double accumulator = 0.0;
    while (this->core->isRunning()) {
        deltaTime = timer.GetDelta();
        accumulator += deltaTime;
        while (accumulator > TIME_STEP) {
            this->update();
            accumulator -= TIME_STEP;
        }
        this->renderer.run();
    }
    SDL_StopTextInput();
}

void Game::update() {
    for (int i = 0; i < 256; i++) {
        if (this->pressDelays[i] > 0) this->pressDelays[i]--;
    }
    handleKeyboard();
    SDL_Event e;
    while (SDL_PollEvent(&e) != 0) {
        switch (e.type) {
            case SDL_QUIT:
                this->core->stop();
                break;
            case SDL_WINDOWEVENT:
                if (e.window.event == SDL_WINDOWEVENT_RESIZED || e.window.event == SDL_WINDOWEVENT_SIZE_CHANGED) {
                    this->renderer.resize((unsigned int) e.window.data1, (unsigned int) e.window.data2);
                }
                break;
            case SDL_KEYDOWN:
            case SDL_KEYUP:
                if (e.key.repeat == 0)
                    handleKeypress(e);
                break;
        }
    }
    this->core->getMap()->update();
    this->core->getMap()->getWorld()->Step(TIME_STEP, 8, 3);
    for (int i = 0; i < this->core->getMap()->getEntities().size(); i++) {
        Entity *entity = this->core->getMap()->getEntities().at(i);
        if (entity->isToBeDeleted()) {
            this->core->getMap()->removeEntity(entity);
            i--;

        }
    }
    this->core->setCamX(-this->core->getCamX() + (this->core->getPlayer()->getX() * this->core->getBlockSize() * this->core->getGeneralScale() + this->core->getCamX()) * 0.05);
    this->core->setCamY(-this->core->getCamY() + (this->core->getPlayer()->getY() * this->core->getBlockSize() * this->core->getGeneralScale() + this->core->getCamY()) * 0.05);
}

void Game::handleKeyboard() {
    float SPEED = 1.0f;
    const Uint8 *keystate = SDL_GetKeyboardState(NULL);
    if (keystate[SDL_SCANCODE_W]) {
        this->core->getPlayer()->setVelY(-SPEED);
    }
    if (keystate[SDL_SCANCODE_S]) {
        this->core->getPlayer()->setVelY(SPEED);
    }
    if (keystate[SDL_SCANCODE_A]) {
        this->core->getPlayer()->setVelX(-SPEED);
    }
    if (keystate[SDL_SCANCODE_D]) {
        this->core->getPlayer()->setVelX(SPEED);
    }
    if (keystate[SDL_SCANCODE_Q]) {
        this->core->stop();
    }
    if (keystate[SDL_SCANCODE_MINUS]) {
        this->core->setBlockSize(this->core->getBlockSize() - 0.15);
    }
    if (keystate[SDL_SCANCODE_EQUALS]) {
        this->core->setBlockSize(this->core->getBlockSize() + 0.15);
    }
}

void Game::handleKeypress(SDL_Event event) {
    switch (event.type) {
        case SDL_KEYDOWN: {
            SDL_Keycode key = event.key.keysym.sym;
            unsigned char delay_tmp = 255;
            static int TELEPORT_DELAY = 255 - 25;
            switch (key) {
                case SDLK_a:
                    if (this->pressDelays[event.key.keysym.sym] > TELEPORT_DELAY) {
                        this->core->getPlayer()->teleport(-1.95, 0);
                        delay_tmp = 0, resetMovementPressDelays();
                    }
                    break;
                case SDLK_d:
                    if (this->pressDelays[event.key.keysym.sym] > TELEPORT_DELAY) {
                        this->core->getPlayer()->teleport(1.95, 0);
                        delay_tmp = 0, resetMovementPressDelays();
                    }
                    break;
                case SDLK_w:
                    if (this->pressDelays[event.key.keysym.sym] > TELEPORT_DELAY) {
                        this->core->getPlayer()->teleport(0, -1.95);
                        delay_tmp = 0, resetMovementPressDelays();
                    }
                    break;
                case SDLK_s:
                    if (this->pressDelays[event.key.keysym.sym] > TELEPORT_DELAY) {
                        this->core->getPlayer()->teleport(0, 1.95);
                        delay_tmp = 0, resetMovementPressDelays();
                    }
                    break;
                case SDLK_c: {
                    double angle = atan2(this->core->getPlayer()->getVelY(), this->core->getPlayer()->getVelX()) + M_PI;
                    EntityBullet *p = new EntityBullet(this->core, angle, 1);
                    p->setX(this->core->getPlayer()->getX() - (this->core->getPlayer()->getWidth() - p->getWidth()) / 2 + 0.5 * cos(angle));
                    p->setY(this->core->getPlayer()->getY() - (this->core->getPlayer()->getHeight() - p->getHeight()) / 2 + 0.5 * sin(angle));
                    this->core->getMap()->addEntity(p);
                    break;
                }
                case SDLK_n: {
                    Player *p = new Player(this->core);
                    p->setX(this->core->getPlayer()->getX() - this->core->getPlayer()->getWidth() / 2);
                    p->setY(this->core->getPlayer()->getY() - this->core->getPlayer()->getHeight() / 2);
                    this->core->getMap()->addEntity(p);
                    break;
                }
                default:
                    break;
            }
            if (event.key.keysym.sym >= 0 && event.key.keysym.sym < 256)
                this->pressDelays[event.key.keysym.sym] = delay_tmp;
            break;
        }
        case SDL_KEYUP:
            break;

        default:
            break;
    }
}

void Game::resetMovementPressDelays() {
    this->pressDelays[SDLK_a] = this->pressDelays[SDLK_d] = this->pressDelays[SDLK_w] = this->pressDelays[SDLK_s] = 0;
}

Game::~Game() {
    delete this->core;
}
<commit_msg>Stabilized camera<commit_after>//
// Created by dar on 11/27/15.
//

#include "Game.h"

Game::Game(Core *core) : core(core), renderer(core) {
}

void Game::run() {
    this->renderer.init();
    SDL_StartTextInput();
    double deltaTime = timer.GetDelta();
    double accumulator = 0.0;
    while (this->core->isRunning()) {
        deltaTime = timer.GetDelta();
        accumulator += deltaTime;
        while (accumulator > TIME_STEP) {
            this->update();
            accumulator -= TIME_STEP;
        }
        this->renderer.run();
    }
    SDL_StopTextInput();
}

void Game::update() {
    for (int i = 0; i < 256; i++) {
        if (this->pressDelays[i] > 0) this->pressDelays[i]--;
    }
    handleKeyboard();
    SDL_Event e;
    while (SDL_PollEvent(&e) != 0) {
        switch (e.type) {
            case SDL_QUIT:
                this->core->stop();
                break;
            case SDL_WINDOWEVENT:
                if (e.window.event == SDL_WINDOWEVENT_RESIZED || e.window.event == SDL_WINDOWEVENT_SIZE_CHANGED) {
                    this->renderer.resize((unsigned int) e.window.data1, (unsigned int) e.window.data2);
                }
                break;
            case SDL_KEYDOWN:
            case SDL_KEYUP:
                if (e.key.repeat == 0)
                    handleKeypress(e);
                break;
        }
    }
    this->core->getMap()->update();
    this->core->getMap()->getWorld()->Step(TIME_STEP, 8, 3);
    for (int i = 0; i < this->core->getMap()->getEntities().size(); i++) {
        Entity *entity = this->core->getMap()->getEntities().at(i);
        if (entity->isToBeDeleted()) {
            this->core->getMap()->removeEntity(entity);
            i--;

        }
    }
    double dx = this->core->getPlayer()->getX() * this->core->getBlockSize() * this->core->getGeneralScale() + this->core->getCamX();
    double dy = this->core->getPlayer()->getY() * this->core->getBlockSize() * this->core->getGeneralScale() + this->core->getCamY();
    if (abs(dx) > 2) this->core->setCamX(-this->core->getCamX() + (dx) * 0.05);
    if (abs(dy) > 2) this->core->setCamY(-this->core->getCamY() + (dy) * 0.05);
}

void Game::handleKeyboard() {
    float SPEED = 1.0f;
    const Uint8 *keystate = SDL_GetKeyboardState(NULL);
    if (keystate[SDL_SCANCODE_W]) {
        this->core->getPlayer()->setVelY(-SPEED);
    }
    if (keystate[SDL_SCANCODE_S]) {
        this->core->getPlayer()->setVelY(SPEED);
    }
    if (keystate[SDL_SCANCODE_A]) {
        this->core->getPlayer()->setVelX(-SPEED);
    }
    if (keystate[SDL_SCANCODE_D]) {
        this->core->getPlayer()->setVelX(SPEED);
    }
    if (keystate[SDL_SCANCODE_Q]) {
        this->core->stop();
    }
    if (keystate[SDL_SCANCODE_MINUS]) {
        this->core->setBlockSize(this->core->getBlockSize() - 0.15);
    }
    if (keystate[SDL_SCANCODE_EQUALS]) {
        this->core->setBlockSize(this->core->getBlockSize() + 0.15);
    }
}

void Game::handleKeypress(SDL_Event event) {
    switch (event.type) {
        case SDL_KEYDOWN: {
            SDL_Keycode key = event.key.keysym.sym;
            unsigned char delay_tmp = 255;
            static int TELEPORT_DELAY = 255 - 25;
            switch (key) {
                case SDLK_a:
                    if (this->pressDelays[event.key.keysym.sym] > TELEPORT_DELAY) {
                        this->core->getPlayer()->teleport(-1.95, 0);
                        delay_tmp = 0, resetMovementPressDelays();
                    }
                    break;
                case SDLK_d:
                    if (this->pressDelays[event.key.keysym.sym] > TELEPORT_DELAY) {
                        this->core->getPlayer()->teleport(1.95, 0);
                        delay_tmp = 0, resetMovementPressDelays();
                    }
                    break;
                case SDLK_w:
                    if (this->pressDelays[event.key.keysym.sym] > TELEPORT_DELAY) {
                        this->core->getPlayer()->teleport(0, -1.95);
                        delay_tmp = 0, resetMovementPressDelays();
                    }
                    break;
                case SDLK_s:
                    if (this->pressDelays[event.key.keysym.sym] > TELEPORT_DELAY) {
                        this->core->getPlayer()->teleport(0, 1.95);
                        delay_tmp = 0, resetMovementPressDelays();
                    }
                    break;
                case SDLK_c: {
                    double angle = atan2(this->core->getPlayer()->getVelY(), this->core->getPlayer()->getVelX()) + M_PI;
                    EntityBullet *p = new EntityBullet(this->core, angle, 1);
                    p->setX(this->core->getPlayer()->getX() - (this->core->getPlayer()->getWidth() - p->getWidth()) / 2 + 0.5 * cos(angle));
                    p->setY(this->core->getPlayer()->getY() - (this->core->getPlayer()->getHeight() - p->getHeight()) / 2 + 0.5 * sin(angle));
                    this->core->getMap()->addEntity(p);
                    break;
                }
                case SDLK_n: {
                    Player *p = new Player(this->core);
                    p->setX(this->core->getPlayer()->getX() - this->core->getPlayer()->getWidth() / 2);
                    p->setY(this->core->getPlayer()->getY() - this->core->getPlayer()->getHeight() / 2);
                    this->core->getMap()->addEntity(p);
                    break;
                }
                default:
                    break;
            }
            if (event.key.keysym.sym >= 0 && event.key.keysym.sym < 256)
                this->pressDelays[event.key.keysym.sym] = delay_tmp;
            break;
        }
        case SDL_KEYUP:
            break;

        default:
            break;
    }
}

void Game::resetMovementPressDelays() {
    this->pressDelays[SDLK_a] = this->pressDelays[SDLK_d] = this->pressDelays[SDLK_w] = this->pressDelays[SDLK_s] = 0;
}

Game::~Game() {
    delete this->core;
}
<|endoftext|>


<commit_before>#include <windows.h>

#include <gl\gl.h>

#ifdef _MSC_VER
#define _USE_MATH_DEFINES
#endif
#include <math.h>

#include "Window.h"
#include "Body.h"
#include "Error.h"
#include "Info.h"

#define NAME_FONT_NAME "Arial"
#define NAME_FONT_SIZE_AT_800_600 24
#define NAME_FONT_SIZE (NAME_FONT_SIZE_AT_800_600*CWindow::GetWidth()/800)

#define NAME_TEXT_COLOR_R 1.00f
#define NAME_TEXT_COLOR_G 1.00f
#define NAME_TEXT_COLOR_B 1.00f
#define NAME_TEXT_COLOR_A 0.50f

#define INFO_FONT_NAME "Arial"
#define INFO_FONT_SIZE_AT_800_600 16
#define INFO_FONT_SIZE (INFO_FONT_SIZE_AT_800_600*CWindow::GetWidth()/800)

#define INFO_TEXT_COLOR_R 1.00f
#define INFO_TEXT_COLOR_G 1.00f
#define INFO_TEXT_COLOR_B 1.00f
#define INFO_TEXT_COLOR_A 0.50f

#define SPACING_COEF 1.75f
#define LINES_AFTER_NAME 1.00f

#define WINDOW_COLOR_R 0.50f
#define WINDOW_COLOR_G 0.50f
#define WINDOW_COLOR_B 0.50f
#define WINDOW_COLOR_A 0.25f

#define WINDOW_RECT_LEFT 0.0125f
#define WINDOW_RECT_RIGHT 0.32f
#define WINDOW_RECT_BOTTOM 0.0125f
#define WINDOW_RECT_TOP 0.27f

#define WINDOW_MARGIN_TOP 0.100f
#define WINDOW_MARGIN_LEFT 0.075f

#define MAX_FADE_TIME 3.0f
#define FADE_TIME_RATIO 0.10f
#define FADE_TIME(totaltime) min(MAX_FADE_TIME, (totaltime)*FADE_TIME_RATIO)

#define WINDOW_POS_X (WINDOW_RECT_LEFT*scrwidth)
#define WINDOW_POS_Y (WINDOW_RECT_TOP*scrheight)
#define WINDOW_WIDTH ((WINDOW_RECT_RIGHT-WINDOW_RECT_LEFT)*scrwidth)
#define WINDOW_HEIGHT ((WINDOW_RECT_TOP-WINDOW_RECT_BOTTOM)*scrheight)
#define MARGIN_WIDTH (WINDOW_WIDTH*WINDOW_MARGIN_LEFT)
#define MARGIN_HEIGHT (WINDOW_HEIGHT*WINDOW_MARGIN_TOP)

CInfo::CInfo()
{
	Init();
}

CInfo::~CInfo()
{
	Free();
}

void CInfo::Init()
{
	loaded=false;
	scrwidth=0;
	scrheight=0;
	winlist=0;
	namelist=infolist=0;
	time=0;
	starttime=endtime=0;
	fadetime=1;
	alpha=0;
}

void CInfo::Free()
{
	nametext.Free();
	infotext.Free();
	if (winlist)
	{
		if (glIsList(winlist))
			glDeleteLists(winlist,3);
	}
	Init();
}

bool CInfo::Load()
{
	Free();

	scrwidth=(float)CWindow::GetWidth();
	scrheight=(float)CWindow::GetHeight();

	winlist=glGenLists(3);
	if (!winlist)
	{
		CError::LogError(WARNING_CODE,"Unable to load planet info - failed to generate display lists.");
		Free();
		return false;
	}
	namelist=winlist+1;
	infolist=namelist+1;

	MakeWindow(winlist);

	loaded=true;
	loaded&=nametext.BuildFTFont(NAME_FONT_NAME,NAME_FONT_SIZE);
	loaded&=infotext.BuildFTFont(INFO_FONT_NAME,INFO_FONT_SIZE);
	if (!loaded)
	{
		CError::LogError(WARNING_CODE,"Unable to load planet info - failed to load font.");
		Free();
	}

	return loaded;
}

void CInfo::MakeWindow(int list)
{
	glNewList(list,GL_COMPILE);
	{
		float l=scrwidth*WINDOW_RECT_LEFT;
		float r=scrwidth*WINDOW_RECT_RIGHT;
		float b=scrheight*WINDOW_RECT_BOTTOM;
		float t=scrheight*WINDOW_RECT_TOP;
		glDisable(GL_TEXTURE_2D);
		glLoadIdentity();
		glBegin(GL_QUADS);
		{
			glVertex2f(l,b);
			glVertex2f(r,b);
			glVertex2f(r,t);
			glVertex2f(l,t);
		}
		glEnd();
	}
	glEndList();
}

void CInfo::GetNameCoords(const char *text, float *x, float *y)
{
	float tw,th;
	nametext.GetTextSize(text,&tw,&th);
	if (x) *x=WINDOW_POS_X+(WINDOW_WIDTH-tw)*0.5f;
	if (y) *y=WINDOW_POS_Y-MARGIN_HEIGHT-th;
}

void CInfo::GetInfoCoords(int linenum, float *x, float *y)
{
	float namey;
	GetNameCoords("",NULL,&namey);
	float nameadd;
	nametext.GetTextSize("",NULL,&nameadd);
	nameadd*=(SPACING_COEF*LINES_AFTER_NAME);

	float th;
	infotext.GetTextSize("",NULL,&th);
	th*=SPACING_COEF*(float)(linenum-1);

	if (x) *x=WINDOW_POS_X+MARGIN_WIDTH;
	if (y) *y=namey-nameadd-th;
}

void CInfo::MakeName(int list, char *targetname)
{
	if (!targetname) return;
	if (*targetname==' ') targetname++;
	float x,y;
	GetNameCoords(targetname,&x,&y);
	glNewList(list,GL_COMPILE);
	{
		glEnable(GL_TEXTURE_2D);
		glLoadIdentity();
		glTranslatef(x,y,0);
		nametext.Print(targetname);
	}
	glEndList();
}

void CInfo::MakeInfoLine(int linenum, char *line)
{
	float x,y;
	GetInfoCoords(linenum,&x,&y);
	glPushMatrix();
	glTranslatef(x,y,0);
	infotext.Print(line);
	glPopMatrix();
}

void CInfo::MakeInfo(int list, CBody *targetbody)
{
	bool star=(targetbody==NULL);
	if (star) targetbody=CBody::bodycache[0];
	glNewList(list,GL_COMPILE);
	{
		int n=0;
		glEnable(GL_TEXTURE_2D);
		glLoadIdentity();
		if (star)
		{
			char line[64];
			n++;
			sprintf(line,"star name: %s",targetbody->name);
			MakeInfoLine(n,line);
		}
		for (int i=0;i<targetbody->info.numlines;i++)
		{
			if (targetbody->info.textlines[i][0]=='/') continue;
			n++;
			MakeInfoLine(n,targetbody->info.textlines[i]);
		}
	}
	glEndList();
}

void CInfo::Start(float seconds, float duration, char *targetname, CBody *targetbody)
{
	if (!loaded)
		return;
	char name[32];
	strcpy(name,targetname);
	int l=strlen(name);
	for (int i=0;i<l;i++)
		if (name[i]=='_')
			name[i]=' ';
	starttime=seconds;
	endtime=starttime+duration;
	fadetime=FADE_TIME(duration);
	MakeName(namelist,name);
	MakeInfo(infolist,targetbody);
}

void CInfo::Update(float seconds)
{
	time=seconds;
	if (time<(endtime-fadetime))
		alpha=min(1,(time-starttime)/fadetime);
	else
		alpha=max(0,(endtime-time)/fadetime);
}

void CInfo::Restart()
{
	starttime-=time;
	endtime-=time;
	time=0;
}

void CInfo::Draw()
{
	if (!alpha || !loaded)
		return;

	glPushAttrib(GL_ENABLE_BIT);

	glDisable(GL_LIGHTING);
	glDisable(GL_DEPTH_TEST);
	glDisable(GL_CULL_FACE);
	glDisable(GL_NORMALIZE);
	glEnable(GL_BLEND);

	glColor4f(WINDOW_COLOR_R,WINDOW_COLOR_G,WINDOW_COLOR_B,WINDOW_COLOR_A*alpha);
	glCallList(winlist);

	glColor4f(NAME_TEXT_COLOR_R,NAME_TEXT_COLOR_G,NAME_TEXT_COLOR_B,NAME_TEXT_COLOR_A*alpha);
	glCallList(namelist);

	glColor4f(INFO_TEXT_COLOR_R,INFO_TEXT_COLOR_G,INFO_TEXT_COLOR_B,INFO_TEXT_COLOR_A*alpha);
	glCallList(infolist);

	glPopAttrib();
}
<commit_msg>Shortcut.<commit_after>#include <windows.h>

#include <gl\gl.h>

#ifdef _MSC_VER
#define _USE_MATH_DEFINES
#endif
#include <math.h>

#include "Window.h"
#include "Body.h"
#include "Error.h"
#include "Info.h"

#define NAME_FONT_NAME "Arial"
#define NAME_FONT_SIZE_AT_800_600 24
#define NAME_FONT_SIZE (NAME_FONT_SIZE_AT_800_600*scrwidth/800)

#define NAME_TEXT_COLOR_R 1.00f
#define NAME_TEXT_COLOR_G 1.00f
#define NAME_TEXT_COLOR_B 1.00f
#define NAME_TEXT_COLOR_A 0.50f

#define INFO_FONT_NAME "Arial"
#define INFO_FONT_SIZE_AT_800_600 16
#define INFO_FONT_SIZE (INFO_FONT_SIZE_AT_800_600*scrwidth/800)

#define INFO_TEXT_COLOR_R 1.00f
#define INFO_TEXT_COLOR_G 1.00f
#define INFO_TEXT_COLOR_B 1.00f
#define INFO_TEXT_COLOR_A 0.50f

#define SPACING_COEF 1.75f
#define LINES_AFTER_NAME 1.00f

#define WINDOW_COLOR_R 0.50f
#define WINDOW_COLOR_G 0.50f
#define WINDOW_COLOR_B 0.50f
#define WINDOW_COLOR_A 0.25f

#define WINDOW_RECT_LEFT 0.0125f
#define WINDOW_RECT_RIGHT 0.32f
#define WINDOW_RECT_BOTTOM 0.0125f
#define WINDOW_RECT_TOP 0.27f

#define WINDOW_MARGIN_TOP 0.100f
#define WINDOW_MARGIN_LEFT 0.075f

#define MAX_FADE_TIME 3.0f
#define FADE_TIME_RATIO 0.10f
#define FADE_TIME(totaltime) min(MAX_FADE_TIME, (totaltime)*FADE_TIME_RATIO)

#define WINDOW_POS_X (WINDOW_RECT_LEFT*scrwidth)
#define WINDOW_POS_Y (WINDOW_RECT_TOP*scrheight)
#define WINDOW_WIDTH ((WINDOW_RECT_RIGHT-WINDOW_RECT_LEFT)*scrwidth)
#define WINDOW_HEIGHT ((WINDOW_RECT_TOP-WINDOW_RECT_BOTTOM)*scrheight)
#define MARGIN_WIDTH (WINDOW_WIDTH*WINDOW_MARGIN_LEFT)
#define MARGIN_HEIGHT (WINDOW_HEIGHT*WINDOW_MARGIN_TOP)

CInfo::CInfo()
{
	Init();
}

CInfo::~CInfo()
{
	Free();
}

void CInfo::Init()
{
	loaded=false;
	scrwidth=0;
	scrheight=0;
	winlist=0;
	namelist=infolist=0;
	time=0;
	starttime=endtime=0;
	fadetime=1;
	alpha=0;
}

void CInfo::Free()
{
	nametext.Free();
	infotext.Free();
	if (winlist)
	{
		if (glIsList(winlist))
			glDeleteLists(winlist,3);
	}
	Init();
}

bool CInfo::Load()
{
	Free();

	scrwidth=(float)CWindow::GetWidth();
	scrheight=(float)CWindow::GetHeight();

	winlist=glGenLists(3);
	if (!winlist)
	{
		CError::LogError(WARNING_CODE,"Unable to load planet info - failed to generate display lists.");
		Free();
		return false;
	}
	namelist=winlist+1;
	infolist=namelist+1;

	MakeWindow(winlist);

	loaded=true;
	loaded&=nametext.BuildFTFont(NAME_FONT_NAME,NAME_FONT_SIZE);
	loaded&=infotext.BuildFTFont(INFO_FONT_NAME,INFO_FONT_SIZE);
	if (!loaded)
	{
		CError::LogError(WARNING_CODE,"Unable to load planet info - failed to load font.");
		Free();
	}

	return loaded;
}

void CInfo::MakeWindow(int list)
{
	glNewList(list,GL_COMPILE);
	{
		float l=scrwidth*WINDOW_RECT_LEFT;
		float r=scrwidth*WINDOW_RECT_RIGHT;
		float b=scrheight*WINDOW_RECT_BOTTOM;
		float t=scrheight*WINDOW_RECT_TOP;
		glDisable(GL_TEXTURE_2D);
		glLoadIdentity();
		glBegin(GL_QUADS);
		{
			glVertex2f(l,b);
			glVertex2f(r,b);
			glVertex2f(r,t);
			glVertex2f(l,t);
		}
		glEnd();
	}
	glEndList();
}

void CInfo::GetNameCoords(const char *text, float *x, float *y)
{
	float tw,th;
	nametext.GetTextSize(text,&tw,&th);
	if (x) *x=WINDOW_POS_X+(WINDOW_WIDTH-tw)*0.5f;
	if (y) *y=WINDOW_POS_Y-MARGIN_HEIGHT-th;
}

void CInfo::GetInfoCoords(int linenum, float *x, float *y)
{
	float namey;
	GetNameCoords("",NULL,&namey);
	float nameadd;
	nametext.GetTextSize("",NULL,&nameadd);
	nameadd*=(SPACING_COEF*LINES_AFTER_NAME);

	float th;
	infotext.GetTextSize("",NULL,&th);
	th*=SPACING_COEF*(float)(linenum-1);

	if (x) *x=WINDOW_POS_X+MARGIN_WIDTH;
	if (y) *y=namey-nameadd-th;
}

void CInfo::MakeName(int list, char *targetname)
{
	if (!targetname) return;
	if (*targetname==' ') targetname++;
	float x,y;
	GetNameCoords(targetname,&x,&y);
	glNewList(list,GL_COMPILE);
	{
		glEnable(GL_TEXTURE_2D);
		glLoadIdentity();
		glTranslatef(x,y,0);
		nametext.Print(targetname);
	}
	glEndList();
}

void CInfo::MakeInfoLine(int linenum, char *line)
{
	float x,y;
	GetInfoCoords(linenum,&x,&y);
	glPushMatrix();
	glTranslatef(x,y,0);
	infotext.Print(line);
	glPopMatrix();
}

void CInfo::MakeInfo(int list, CBody *targetbody)
{
	bool star=(targetbody==NULL);
	if (star) targetbody=CBody::bodycache[0];
	glNewList(list,GL_COMPILE);
	{
		int n=0;
		glEnable(GL_TEXTURE_2D);
		glLoadIdentity();
		if (star)
		{
			char line[64];
			n++;
			sprintf(line,"star name: %s",targetbody->name);
			MakeInfoLine(n,line);
		}
		for (int i=0;i<targetbody->info.numlines;i++)
		{
			if (targetbody->info.textlines[i][0]=='/') continue;
			n++;
			MakeInfoLine(n,targetbody->info.textlines[i]);
		}
	}
	glEndList();
}

void CInfo::Start(float seconds, float duration, char *targetname, CBody *targetbody)
{
	if (!loaded)
		return;
	char name[32];
	strcpy(name,targetname);
	int l=strlen(name);
	for (int i=0;i<l;i++)
		if (name[i]=='_')
			name[i]=' ';
	starttime=seconds;
	endtime=starttime+duration;
	fadetime=FADE_TIME(duration);
	MakeName(namelist,name);
	MakeInfo(infolist,targetbody);
}

void CInfo::Update(float seconds)
{
	time=seconds;
	if (time<(endtime-fadetime))
		alpha=min(1,(time-starttime)/fadetime);
	else
		alpha=max(0,(endtime-time)/fadetime);
}

void CInfo::Restart()
{
	starttime-=time;
	endtime-=time;
	time=0;
}

void CInfo::Draw()
{
	if (!alpha || !loaded)
		return;

	glPushAttrib(GL_ENABLE_BIT);

	glDisable(GL_LIGHTING);
	glDisable(GL_DEPTH_TEST);
	glDisable(GL_CULL_FACE);
	glDisable(GL_NORMALIZE);
	glEnable(GL_BLEND);

	glColor4f(WINDOW_COLOR_R,WINDOW_COLOR_G,WINDOW_COLOR_B,WINDOW_COLOR_A*alpha);
	glCallList(winlist);

	glColor4f(NAME_TEXT_COLOR_R,NAME_TEXT_COLOR_G,NAME_TEXT_COLOR_B,NAME_TEXT_COLOR_A*alpha);
	glCallList(namelist);

	glColor4f(INFO_TEXT_COLOR_R,INFO_TEXT_COLOR_G,INFO_TEXT_COLOR_B,INFO_TEXT_COLOR_A*alpha);
	glCallList(infolist);

	glPopAttrib();
}
<|endoftext|>


<commit_before>/*!
 * ws: a node.js websocket client
 * Copyright(c) 2011 Einar Otto Stangvik <einaros@gmail.com>
 * MIT Licensed
 */

#include <v8.h>
#include <node.h>
#include <node_version.h>
#include <node_buffer.h>
#include <node_object_wrap.h>
#include <stdlib.h>
#include <string.h>
#include <wchar.h>
#include <stdio.h>
#include "nan.h"

using namespace v8;
using namespace node;

class BufferUtil : public ObjectWrap
{
public:

  static void Initialize(v8::Handle<v8::Object> target)
  {
    NanScope();
    Local<FunctionTemplate> t = NanNew<FunctionTemplate>(New);
    t->InstanceTemplate()->SetInternalFieldCount(1);
    NODE_SET_METHOD(t, "unmask", BufferUtil::Unmask);
    NODE_SET_METHOD(t, "mask", BufferUtil::Mask);
    NODE_SET_METHOD(t, "merge", BufferUtil::Merge);
    target->Set(NanNew<String>("BufferUtil"), t->GetFunction());
  }

protected:

  static NAN_METHOD(New)
  {
    NanScope();
    BufferUtil* bufferUtil = new BufferUtil();
    bufferUtil->Wrap(args.This());
    NanReturnValue(args.This());
  }

  static NAN_METHOD(Merge)
  {
    NanScope();
    Local<Object> bufferObj = args[0]->ToObject();
    char* buffer = Buffer::Data(bufferObj);
    Local<Array> array = Local<Array>::Cast(args[1]);
    unsigned int arrayLength = array->Length();
    size_t offset = 0;
    unsigned int i;
    for (i = 0; i < arrayLength; ++i) {
      Local<Object> src = array->Get(i)->ToObject();
      size_t length = Buffer::Length(src);
      memcpy(buffer + offset, Buffer::Data(src), length);
      offset += length;
    }
    NanReturnValue(NanTrue());
  }

  static NAN_METHOD(Unmask)
  {
    NanScope();
    Local<Object> buffer_obj = args[0]->ToObject();
    size_t length = Buffer::Length(buffer_obj);
    Local<Object> mask_obj = args[1]->ToObject();
    unsigned int *mask = (unsigned int*)Buffer::Data(mask_obj);
    unsigned int* from = (unsigned int*)Buffer::Data(buffer_obj);
    size_t len32 = length / 4;
    unsigned int i;
    for (i = 0; i < len32; ++i) *(from + i) ^= *mask;
    from += i;
    switch (length % 4) {
      case 3: *((unsigned char*)from+2) = *((unsigned char*)from+2) ^ ((unsigned char*)mask)[2];
      case 2: *((unsigned char*)from+1) = *((unsigned char*)from+1) ^ ((unsigned char*)mask)[1];
      case 1: *((unsigned char*)from  ) = *((unsigned char*)from  ) ^ ((unsigned char*)mask)[0];
      case 0:;
    }
    NanReturnValue(NanTrue());
  }

  static NAN_METHOD(Mask)
  {
    NanScope();
    Local<Object> buffer_obj = args[0]->ToObject();
    Local<Object> mask_obj = args[1]->ToObject();
    unsigned int *mask = (unsigned int*)Buffer::Data(mask_obj);
    Local<Object> output_obj = args[2]->ToObject();
    unsigned int dataOffset = args[3]->Int32Value();
    unsigned int length = args[4]->Int32Value();
    unsigned int* to = (unsigned int*)(Buffer::Data(output_obj) + dataOffset);
    unsigned int* from = (unsigned int*)Buffer::Data(buffer_obj);
    unsigned int len32 = length / 4;
    unsigned int i;
    for (i = 0; i < len32; ++i) *(to + i) = *(from + i) ^ *mask;
    to += i;
    from += i;
    switch (length % 4) {
      case 3: *((unsigned char*)to+2) = *((unsigned char*)from+2) ^ *((unsigned char*)mask+2);
      case 2: *((unsigned char*)to+1) = *((unsigned char*)from+1) ^ *((unsigned char*)mask+1);
      case 1: *((unsigned char*)to  ) = *((unsigned char*)from  ) ^ *((unsigned char*)mask);
      case 0:;
    }
    NanReturnValue(NanTrue());
  }
};

#if !NODE_VERSION_AT_LEAST(0,10,0)
extern "C"
#endif
void init (Handle<Object> target)
{
  NanScope();
  BufferUtil::Initialize(target);
}

NODE_MODULE(bufferutil, init)

<commit_msg>[fix] Correct the license<commit_after>/*!
 * bufferutil: WebSocket buffer utils
 * Copyright(c) 2015 Einar Otto Stangvik <einaros@gmail.com>
 * MIT Licensed
 */

#include <v8.h>
#include <node.h>
#include <node_version.h>
#include <node_buffer.h>
#include <node_object_wrap.h>
#include <stdlib.h>
#include <string.h>
#include <wchar.h>
#include <stdio.h>
#include "nan.h"

using namespace v8;
using namespace node;

class BufferUtil : public ObjectWrap
{
public:

  static void Initialize(v8::Handle<v8::Object> target)
  {
    NanScope();
    Local<FunctionTemplate> t = NanNew<FunctionTemplate>(New);
    t->InstanceTemplate()->SetInternalFieldCount(1);
    NODE_SET_METHOD(t, "unmask", BufferUtil::Unmask);
    NODE_SET_METHOD(t, "mask", BufferUtil::Mask);
    NODE_SET_METHOD(t, "merge", BufferUtil::Merge);
    target->Set(NanNew<String>("BufferUtil"), t->GetFunction());
  }

protected:

  static NAN_METHOD(New)
  {
    NanScope();
    BufferUtil* bufferUtil = new BufferUtil();
    bufferUtil->Wrap(args.This());
    NanReturnValue(args.This());
  }

  static NAN_METHOD(Merge)
  {
    NanScope();
    Local<Object> bufferObj = args[0]->ToObject();
    char* buffer = Buffer::Data(bufferObj);
    Local<Array> array = Local<Array>::Cast(args[1]);
    unsigned int arrayLength = array->Length();
    size_t offset = 0;
    unsigned int i;
    for (i = 0; i < arrayLength; ++i) {
      Local<Object> src = array->Get(i)->ToObject();
      size_t length = Buffer::Length(src);
      memcpy(buffer + offset, Buffer::Data(src), length);
      offset += length;
    }
    NanReturnValue(NanTrue());
  }

  static NAN_METHOD(Unmask)
  {
    NanScope();
    Local<Object> buffer_obj = args[0]->ToObject();
    size_t length = Buffer::Length(buffer_obj);
    Local<Object> mask_obj = args[1]->ToObject();
    unsigned int *mask = (unsigned int*)Buffer::Data(mask_obj);
    unsigned int* from = (unsigned int*)Buffer::Data(buffer_obj);
    size_t len32 = length / 4;
    unsigned int i;
    for (i = 0; i < len32; ++i) *(from + i) ^= *mask;
    from += i;
    switch (length % 4) {
      case 3: *((unsigned char*)from+2) = *((unsigned char*)from+2) ^ ((unsigned char*)mask)[2];
      case 2: *((unsigned char*)from+1) = *((unsigned char*)from+1) ^ ((unsigned char*)mask)[1];
      case 1: *((unsigned char*)from  ) = *((unsigned char*)from  ) ^ ((unsigned char*)mask)[0];
      case 0:;
    }
    NanReturnValue(NanTrue());
  }

  static NAN_METHOD(Mask)
  {
    NanScope();
    Local<Object> buffer_obj = args[0]->ToObject();
    Local<Object> mask_obj = args[1]->ToObject();
    unsigned int *mask = (unsigned int*)Buffer::Data(mask_obj);
    Local<Object> output_obj = args[2]->ToObject();
    unsigned int dataOffset = args[3]->Int32Value();
    unsigned int length = args[4]->Int32Value();
    unsigned int* to = (unsigned int*)(Buffer::Data(output_obj) + dataOffset);
    unsigned int* from = (unsigned int*)Buffer::Data(buffer_obj);
    unsigned int len32 = length / 4;
    unsigned int i;
    for (i = 0; i < len32; ++i) *(to + i) = *(from + i) ^ *mask;
    to += i;
    from += i;
    switch (length % 4) {
      case 3: *((unsigned char*)to+2) = *((unsigned char*)from+2) ^ *((unsigned char*)mask+2);
      case 2: *((unsigned char*)to+1) = *((unsigned char*)from+1) ^ *((unsigned char*)mask+1);
      case 1: *((unsigned char*)to  ) = *((unsigned char*)from  ) ^ *((unsigned char*)mask);
      case 0:;
    }
    NanReturnValue(NanTrue());
  }
};

#if !NODE_VERSION_AT_LEAST(0,10,0)
extern "C"
#endif
void init (Handle<Object> target)
{
  NanScope();
  BufferUtil::Initialize(target);
}

NODE_MODULE(bufferutil, init)

<|endoftext|>


<commit_before>// -*- mode: c++, encoding: utf-8 -*-
/**
 * tbrpg – Text based roll playing game
 *
 * Copyright © 2012  Mattias Andrée (maandree@kth.se)
 *
 * 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 3 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, see <http://www.gnu.org/licenses/>.
 */
#ifndef __CHARACTER__
#define __CHARACTER__

#include <stdlib.h>
#include <algorithm>
#include <string>

/**
 * Text based roll playing game
 *
 * DD2387 Program construction with C++
 * Laboration 3
 *
 * @author  Mattias Andrée <maandree@kth.se>
 */
namespace tbrpg
{
  /**
   * Character class
   */
  class Character
  {
  public:
    /**
     * Gender: female
     */
    const static bool FEMALE = false;

    /**
     * Gender: male
     */
    const static bool MALE = true;

    /**
     * Alignment: lawful good
     */
    const static char LAWFUL_GOOD = 8;

    /**
     * Alignment: neutral good
     */
    const static char NEUTRAL_GOOD = 7;

    /**
     * Alignment: chaotic good
     */
    const static char CHAOTIC_GOOD = 6;

    /**
     * Alignment: lawful neutral
     */
    const static char LAWFUL_NEUTRAL = 5;

    /**
     * Alignment: neutral
     */
    const static char TRUE_NEUTRAL = 4;

    /**
     * Alignment: chaotic neutral
     */
    const static char CHAOTIC_NEUTRAL = 3;

    /**
     * Alignment: lawful evil
     */
    const static char LAWFUL_EVIL = 2;

    /**
     * Alignment: neutral evil
     */
    const static char NEUTRAL_EVIL = 1;

    /**
     * Alignment: chaotic evil
     */
    const static char CHAOTIC_EVIL = 0;

  protected:
    /**
     * The gender of the character
     */
    bool gender;

    /**
     * The name of the character
     */
    std::string name;

    /**
     * Optional image, no bigger than 80x80 pixels
     */
    std::string image;

    /**
     * ANSI colour value used on the character name
     */
    char colour;

    /**
     * Character alignment
     */
    char alignment;

    /**
     * The characters reputation
     */
    char reputation;

    /**
     * The character's strength
     */
    char strength;

    /**
     * The character's constitution
     */
    char constitution;

    /**
     * The character's dexterity
     */
    char dexterity;

    /**
     * The character's intelligence
     */
    char intelligence;

    /**
     * The character's wisdom
     */
    char wisdom;

    /**
     * The character's charisma
     */
    char charisma;

  public:
    /**
     * Constructor
     */
    Character();

    /**
     * Copy constructor
     *
     * @param  original  The object to clone
     */
    Character(const Character& original);

    /**
     * Copy constructor
     *
     * @param  original  The object to clone
     */
    Character(Character& original);

    /**
     * Move constructor
     *
     * @param  original  The object to clone
     */
    Character(Character&& original);

    /**
     * Destructor
     */
    virtual ~Character();

    /**
     * Assignment operator
     *
     * @param   original  The reference object
     * @return            The invoked object
     */
    virtual Character& operator =(const Character& original);

    /**
     * Assignment operator
     *
     * @param   original  The reference object
     * @return            The invoked object
     */
    virtual Character& operator =(Character& original);

    /**
     * Move operator
     *
     * @param   original  The moved object, its resourced will be moved
     * @return            The invoked object
     */
    virtual Character& operator =(Character&& original);

  };
}

#endif//__ITEM__

<commit_msg>remove character.hpp<commit_after><|endoftext|>


<commit_before>//
//  client-cpp.cc
//  C++ CORBA client interface for SceneViewer.
//
//  Created by Mathieu Geisert in December 2014.
//  Copyright (c) 2014 LAAS-CNRS. All rights reserved.
//

#include <gepetto/viewer/corba/client.hh>

namespace graphics {
namespace corbaServer {

void ClientCpp::se3ToCorba(CORBA::Double* corbaPosition, const se3::SE3& se3position)
{
    Eigen::Quaternion<double> q(se3position.rotation());
    corbaPosition[0] = se3position.translation()(0);
    corbaPosition[1] = se3position.translation()(1);
    corbaPosition[2] = se3position.translation()(2);
    corbaPosition[3] = q.w();
    corbaPosition[4] = q.x();
    corbaPosition[5] = q.y();
    corbaPosition[5] = q.z();
}

ClientCpp::ClientCpp()
{
    int    argc=0;       // Dummy variables to support following call.
    char** argv=0;
    orb_ = CORBA::ORB_init(argc, argv);

    // Get a reference to the Naming Service
    CORBA::Object_var rootContextObj =
        orb_->resolve_initial_references("NameService");
    CosNaming::NamingContext_var nc =
	CosNaming::NamingContext::_narrow(rootContextObj.in());

    CosNaming::Name name;
    name.length(2);
    name[0].id = (const char *) "gepetto";
    name[0].kind = (const char *) "viewer";
    name[1].id = (const char *) "corbaserver";
    name[1].kind = (const char *) "gui";
    // Invoke the root context to retrieve the object reference
    CORBA::Object_var managerObj = nc->resolve(name);
    // Narrow the previous object to obtain the correct type
    manager_ =
      gepetto::corbaserver::GraphicalInterface::_narrow(managerObj.in());
}

ClientCpp::~ClientCpp()
{
    //manager_->shutdown();
    if (!CORBA::is_nil(orb_)) {
	try {
	    orb_->destroy();
	    std::cout << "Ending CORBA..." << std::endl;
	} catch(const CORBA::Exception& e) {
	    std::cout << "orb->destroy failed" << std::endl;
	}
    }
}

void ClientCpp::getNodeList()
{
   manager_->getNodeList();
}

void ClientCpp::getWindowList()
{
   manager_->getWindowList();
}

bool ClientCpp::setRate(int  rate)
{
   return manager_->setRate(rate);
}

void ClientCpp::refresh()
{
    manager_->refresh();
}

ClientCpp::WindowID ClientCpp::createWindow(const char* windowName)
{
    return manager_->createWindow(windowName);
}

    //void ClientCpp::createWindow(const char* name, CORBA::ULong x, CORBA::ULong y, CORBA::ULong width, CORBA::ULong height) ;

void ClientCpp::createScene(const char* sceneName)
{
  manager_->createScene(sceneName);
}

void ClientCpp::createSceneWithFloor(const char* sceneName)
{
  manager_->createSceneWithFloor(sceneName);
}

bool ClientCpp::addSceneToWindow(const char* sceneName, const ClientCpp::WindowID windowId)
{
   return  manager_->addSceneToWindow(sceneName, windowId);
}

/*bool ClientCpp::addBox(const char* boxName, float boxSize1, float boxSize2, float boxSize3)
{
    return manager_->addBox(boxName, boxSize1, boxSize2, boxSize3);
}*/

bool ClientCpp::addBox(const char* boxName, const float boxSize1, const float boxSize2, const float boxSize3, const double* color)
{
    return manager_->addBox(boxName, boxSize1, boxSize2, boxSize3, color);
}

/*bool ClientCpp::addCapsule(const char* capsuleName, float radius, float height)
{
    return manager_->addCapsule(capsuleName, radius, height);
}*/

bool ClientCpp::addCapsule(const char* capsuleName, const float radius, const float height, const double* color)
{
    return manager_->addCapsule(capsuleName, radius, height, color);
}

bool ClientCpp::addMesh(const char* meshName, const char* meshPath)
{
    return manager_->addMesh(meshName, meshPath);
}

/*bool ClientCpp::addCone(const char* coneName, float radius, float height)
{
    return manager_->addCone(coneName, radius, height);
}*/

bool ClientCpp::addCone(const char* coneName, const float radius, const float height, const double* color)
{
    return manager_->addCone(coneName, radius, height, color);
}

/*bool ClientCpp::addCylinder(const char* cylinderName, float radius, float height)
{
    return manager_->addCylinder(cylinderName, radius, height);
}*/

bool ClientCpp::addCylinder(const char* cylinderName, const float radius, const float height, const double* color)
{
    return manager_->addCylinder(cylinderName, radius, height, color);
}

/*bool ClientCpp::addSphere(const char* sphereName, float radius)
{
    return manager_->addSphere(sphereName, radius);
}*/

bool ClientCpp::addSphere(const char* sphereName, const float radius, const double* color)
{
    return manager_->addSphere(sphereName, radius, color);
}

bool ClientCpp::addLine(const char* lineName, const double* pos1, const double* pos2, const double* color)
{
    return manager_->addLine(lineName, pos1, pos2, color);
}

bool ClientCpp::addTriangleFace(const char* faceName, const double* pos1, const double* pos2, const double* pos3, const double* color)
{
    return manager_->addTriangleFace(faceName, pos1, pos2, pos3, color);
}

bool ClientCpp::addSquareFace(const char* faceName, const double* pos1, const double* pos2, const double* pos3, const double* pos4, const double* color)
{
    return manager_->addSquareFace(faceName, pos1, pos2, pos3, pos4, color);
}

bool ClientCpp::addURDF(const char* urdfName, const char* urdfPath, const char* urdfPackagePath)
{
    return manager_->addURDF(urdfName, urdfPath, urdfPackagePath);
}

bool ClientCpp::createGroup(const char* groupName)
{
    return manager_->createGroup(groupName);
}

bool ClientCpp::addToGroup(const char* nodeName, const char* groupName)
{
    return manager_->addToGroup(nodeName, groupName);
}

bool ClientCpp::applyConfiguration(const char* nodeName, const se3::SE3& se3position)
{
    CORBA::Double corbaPosition[7];
    ClientCpp::se3ToCorba(corbaPosition, se3position);
    return manager_->applyConfiguration(nodeName, corbaPosition);
}

bool ClientCpp::setVisibility(const char* nodeName, const char* visibilityMode)
{
    return manager_->setVisibility(nodeName, visibilityMode);
}

bool ClientCpp::setWireFrameMode(const char* nodeName, const char* wireFrameMode)
{
    return manager_->setWireFrameMode(nodeName, wireFrameMode);
}
bool ClientCpp::setLightingMode(const char* nodeName, const char* lightingMode)
{
    return manager_->setLightingMode(nodeName, lightingMode);
}

bool ClientCpp::startCapture (const WindowID windowId, const char* filename, const char* extension)
{
  return manager_->startCapture (windowId, filename, extension);
}

bool ClientCpp::stopCapture (const WindowID windowId)
{
  return manager_->stopCapture (windowId);
}

bool ClientCpp::writeNodeFile (const WindowID windowId, const char* filename)
{
  return manager_->writeNodeFile (windowId, filename);
}

} // end of namespace corbaserver
} // end of namespace graphics
<commit_msg>[Bug fixed] Fix bug about se3 transformation to corba data<commit_after>//
//  client-cpp.cc
//  C++ CORBA client interface for SceneViewer.
//
//  Created by Mathieu Geisert in December 2014.
//  Copyright (c) 2014 LAAS-CNRS. All rights reserved.
//

#include <gepetto/viewer/corba/client.hh>

namespace graphics {
namespace corbaServer {

void ClientCpp::se3ToCorba(CORBA::Double* corbaPosition, const se3::SE3& se3position)
{
    Eigen::Quaternion<double> q(se3position.rotation());
    corbaPosition[0] = se3position.translation()(0);
    corbaPosition[1] = se3position.translation()(1);
    corbaPosition[2] = se3position.translation()(2);
    corbaPosition[3] = q.w();
    corbaPosition[4] = q.x();
    corbaPosition[5] = q.y();
    corbaPosition[6] = q.z();
}

ClientCpp::ClientCpp()
{
    int    argc=0;       // Dummy variables to support following call.
    char** argv=0;
    orb_ = CORBA::ORB_init(argc, argv);

    // Get a reference to the Naming Service
    CORBA::Object_var rootContextObj =
        orb_->resolve_initial_references("NameService");
    CosNaming::NamingContext_var nc =
	CosNaming::NamingContext::_narrow(rootContextObj.in());

    CosNaming::Name name;
    name.length(2);
    name[0].id = (const char *) "gepetto";
    name[0].kind = (const char *) "viewer";
    name[1].id = (const char *) "corbaserver";
    name[1].kind = (const char *) "gui";
    // Invoke the root context to retrieve the object reference
    CORBA::Object_var managerObj = nc->resolve(name);
    // Narrow the previous object to obtain the correct type
    manager_ =
      gepetto::corbaserver::GraphicalInterface::_narrow(managerObj.in());
}

ClientCpp::~ClientCpp()
{
    //manager_->shutdown();
    if (!CORBA::is_nil(orb_)) {
	try {
	    orb_->destroy();
	    std::cout << "Ending CORBA..." << std::endl;
	} catch(const CORBA::Exception& e) {
	    std::cout << "orb->destroy failed" << std::endl;
	}
    }
}

void ClientCpp::getNodeList()
{
   manager_->getNodeList();
}

void ClientCpp::getWindowList()
{
   manager_->getWindowList();
}

bool ClientCpp::setRate(int  rate)
{
   return manager_->setRate(rate);
}

void ClientCpp::refresh()
{
    manager_->refresh();
}

ClientCpp::WindowID ClientCpp::createWindow(const char* windowName)
{
    return manager_->createWindow(windowName);
}

    //void ClientCpp::createWindow(const char* name, CORBA::ULong x, CORBA::ULong y, CORBA::ULong width, CORBA::ULong height) ;

void ClientCpp::createScene(const char* sceneName)
{
  manager_->createScene(sceneName);
}

void ClientCpp::createSceneWithFloor(const char* sceneName)
{
  manager_->createSceneWithFloor(sceneName);
}

bool ClientCpp::addSceneToWindow(const char* sceneName, const ClientCpp::WindowID windowId)
{
   return  manager_->addSceneToWindow(sceneName, windowId);
}

/*bool ClientCpp::addBox(const char* boxName, float boxSize1, float boxSize2, float boxSize3)
{
    return manager_->addBox(boxName, boxSize1, boxSize2, boxSize3);
}*/

bool ClientCpp::addBox(const char* boxName, const float boxSize1, const float boxSize2, const float boxSize3, const double* color)
{
    return manager_->addBox(boxName, boxSize1, boxSize2, boxSize3, color);
}

/*bool ClientCpp::addCapsule(const char* capsuleName, float radius, float height)
{
    return manager_->addCapsule(capsuleName, radius, height);
}*/

bool ClientCpp::addCapsule(const char* capsuleName, const float radius, const float height, const double* color)
{
    return manager_->addCapsule(capsuleName, radius, height, color);
}

bool ClientCpp::addMesh(const char* meshName, const char* meshPath)
{
    return manager_->addMesh(meshName, meshPath);
}

/*bool ClientCpp::addCone(const char* coneName, float radius, float height)
{
    return manager_->addCone(coneName, radius, height);
}*/

bool ClientCpp::addCone(const char* coneName, const float radius, const float height, const double* color)
{
    return manager_->addCone(coneName, radius, height, color);
}

/*bool ClientCpp::addCylinder(const char* cylinderName, float radius, float height)
{
    return manager_->addCylinder(cylinderName, radius, height);
}*/

bool ClientCpp::addCylinder(const char* cylinderName, const float radius, const float height, const double* color)
{
    return manager_->addCylinder(cylinderName, radius, height, color);
}

/*bool ClientCpp::addSphere(const char* sphereName, float radius)
{
    return manager_->addSphere(sphereName, radius);
}*/

bool ClientCpp::addSphere(const char* sphereName, const float radius, const double* color)
{
    return manager_->addSphere(sphereName, radius, color);
}

bool ClientCpp::addLine(const char* lineName, const double* pos1, const double* pos2, const double* color)
{
    return manager_->addLine(lineName, pos1, pos2, color);
}

bool ClientCpp::addTriangleFace(const char* faceName, const double* pos1, const double* pos2, const double* pos3, const double* color)
{
    return manager_->addTriangleFace(faceName, pos1, pos2, pos3, color);
}

bool ClientCpp::addSquareFace(const char* faceName, const double* pos1, const double* pos2, const double* pos3, const double* pos4, const double* color)
{
    return manager_->addSquareFace(faceName, pos1, pos2, pos3, pos4, color);
}

bool ClientCpp::addURDF(const char* urdfName, const char* urdfPath, const char* urdfPackagePath)
{
    return manager_->addURDF(urdfName, urdfPath, urdfPackagePath);
}

bool ClientCpp::createGroup(const char* groupName)
{
    return manager_->createGroup(groupName);
}

bool ClientCpp::addToGroup(const char* nodeName, const char* groupName)
{
    return manager_->addToGroup(nodeName, groupName);
}

bool ClientCpp::applyConfiguration(const char* nodeName, const se3::SE3& se3position)
{
    CORBA::Double corbaPosition[7];
    ClientCpp::se3ToCorba(corbaPosition, se3position);
    return manager_->applyConfiguration(nodeName, corbaPosition);
}

bool ClientCpp::setVisibility(const char* nodeName, const char* visibilityMode)
{
    return manager_->setVisibility(nodeName, visibilityMode);
}

bool ClientCpp::setWireFrameMode(const char* nodeName, const char* wireFrameMode)
{
    return manager_->setWireFrameMode(nodeName, wireFrameMode);
}
bool ClientCpp::setLightingMode(const char* nodeName, const char* lightingMode)
{
    return manager_->setLightingMode(nodeName, lightingMode);
}

bool ClientCpp::startCapture (const WindowID windowId, const char* filename, const char* extension)
{
  return manager_->startCapture (windowId, filename, extension);
}

bool ClientCpp::stopCapture (const WindowID windowId)
{
  return manager_->stopCapture (windowId);
}

bool ClientCpp::writeNodeFile (const WindowID windowId, const char* filename)
{
  return manager_->writeNodeFile (windowId, filename);
}

} // end of namespace corbaserver
} // end of namespace graphics
<|endoftext|>


<commit_before>#include "Ruby.h"
#include "RubyObject.h"
#include "common.h"
#include <cstring>
#include <string>

using namespace v8;

Persistent<Function> Ruby::s_getCtor;
VALUE Ruby::BLOCK_WRAPPER_CLASS;

void Ruby::Init(Handle<Object> module)
{
  static char* argv[] = { (char*)"norby", (char*)"-e", (char*)"" };

  RUBY_INIT_STACK;
  ruby_init();
  ruby_options(3, argv);

  BLOCK_WRAPPER_CLASS = rb_define_class("BlockWrapper", rb_cObject);

  node::AtExit(Cleanup);

  module->Set(NanNew<String>("exports"),
              NanNew<FunctionTemplate>(New)->GetFunction());
}

void Ruby::Cleanup(void*)
{
  log("Cleaning up!");
  RubyObject::Cleanup();
  ruby_cleanup(0);
}

NAN_METHOD(Ruby::New)
{
  NanScope();

  assert(args[0]->IsFunction());
  NanAssignPersistent(s_getCtor, args[0].As<Function>());

  Local<Object> bindings = NanNew<Object>();
  NODE_SET_METHOD(bindings, "_getClass", GetClass);
  NODE_SET_METHOD(bindings, "_defineClass", DefineClass);
  NODE_SET_METHOD(bindings, "eval", Eval);
  NODE_SET_METHOD(bindings, "getMethod", GetMethod);
  // TODO: Maybe we should load the constants here and place them in an object?
  NODE_SET_METHOD(bindings, "getConstant", GetConstant);

  NanReturnValue(bindings);
}

Local<Function> Ruby::GetCtor(Local<Function> rubyClass)
{
  NanEscapableScope();

  Local<Function> getCtor = NanNew<Function>(s_getCtor);
  Handle<Value> argv[] = { rubyClass };
  return NanEscapeScope(NanMakeCallback(NanGetCurrentContext()->Global(),
                                        getCtor, 1, argv).As<Function>());
}

struct ConstGetter
{
  ConstGetter(Handle<Value> nv) : nameVal(nv) {}
  VALUE operator()() const
  {
    NanScope();

    Local<String> constName = nameVal->ToString();
    String::Utf8Value constStr(constName);

    ID id;
    VALUE mod;
    const char* split = std::strstr(*constStr, "::");
    if (split) {
      id = rb_intern(split + 2);
      mod = rb_const_get(rb_cObject, rb_intern2(*constStr, split - *constStr));
    }
    else {
      id = rb_intern2(*constStr, constStr.length());
      mod = rb_cObject;
    }

    return rb_const_get(mod, id);
  }

  Handle<Value> nameVal;
};

// TODO: Should/could we combine this with RubyObject::GetClass?
NAN_METHOD(Ruby::GetClass)
{
  NanScope();

  VALUE klass;
  SAFE_RUBY_CALL(klass, ConstGetter(args[0]));

  if (TYPE(klass) != T_CLASS) {
    std::string msg(*String::Utf8Value(args[0]));
    msg.append(" is not a class");
    NanThrowTypeError(msg.c_str());
    NanReturnUndefined();
  }

  NanReturnValue(RubyObject::GetClass(klass));
}

struct ClassDefiner
{
  ClassDefiner(Handle<Value> nv, VALUE s) : nameVal(nv), super(s) {}
  VALUE operator()() const
  {
    NanScope();

    Local<String> className = nameVal->ToString();
    return rb_define_class(*String::Utf8Value(className), super);
  }

  Handle<Value> nameVal;
  VALUE super;
};

NAN_METHOD(Ruby::DefineClass)
{
  NanScope();

  Local<String> name = args[0]->ToString();
  log("Inherit called for " << *String::Utf8Value(name));

  VALUE super;
  SAFE_RUBY_CALL(super, ConstGetter(args[1]));
  VALUE klass;
  SAFE_RUBY_CALL(klass, ClassDefiner(args[0], super));

  NanReturnValue(RubyObject::GetClass(klass));
}

struct EvalCaller
{
  EvalCaller(const char* s) : str(s) {}
  VALUE operator()() const
  {
    return rb_eval_string(str);
  }

  const char* str;
};

NAN_METHOD(Ruby::Eval)
{
  NanScope();

  Local<String> str = args[0]->ToString();
  VALUE res;
  SAFE_RUBY_CALL(res, EvalCaller(*String::Utf8Value(str)));

  NanReturnValue(rubyToV8(res));
}

NAN_METHOD(CallMethod)
{
  NanScope();
  NanReturnValue(CallRubyFromV8(rb_cObject, args));
}

// TODO: Should this throw immediately if the function doesnt exist?
NAN_METHOD(Ruby::GetMethod)
{
  NanScope();

  Local<String> name = args[0]->ToString();
  ID methodID = rb_intern(*String::Utf8Value(name));
  Local<Function> func =
    NanNew<FunctionTemplate>(CallMethod, EXTERNAL_WRAP((void*)methodID))->GetFunction();
  func->SetName(name);

  NanReturnValue(func);
}

NAN_METHOD(Ruby::GetConstant)
{
  NanScope();

  VALUE constant;
  SAFE_RUBY_CALL(constant, ConstGetter(args[0]));

  // TODO: Should we allow getting classes this way? Maybe throw an exception?
  NanReturnValue(rubyToV8(constant));
}
<commit_msg>Fixed compiler warning<commit_after>#include "Ruby.h"
#include "RubyObject.h"
#include "common.h"
#include <cstring>
#include <string>

using namespace v8;

Persistent<Function> Ruby::s_getCtor;
VALUE Ruby::BLOCK_WRAPPER_CLASS;

void Ruby::Init(Handle<Object> module)
{
  static char* argv[] = { (char*)"norby", (char*)"-e", (char*)"" };

  RUBY_INIT_STACK;
  ruby_init();
  ruby_options(3, argv);

  BLOCK_WRAPPER_CLASS = rb_define_class("BlockWrapper", rb_cObject);

  node::AtExit(Cleanup);

  module->Set(NanNew<String>("exports"),
              NanNew<FunctionTemplate>(New)->GetFunction());
}

void Ruby::Cleanup(void*)
{
  log("Cleaning up!");
  RubyObject::Cleanup();
  ruby_cleanup(0);
}

NAN_METHOD(Ruby::New)
{
  NanScope();

  assert(args[0]->IsFunction());
  NanAssignPersistent(s_getCtor, args[0].As<Function>());

  Local<Object> bindings = NanNew<Object>();
  NODE_SET_METHOD(bindings, "_getClass", GetClass);
  NODE_SET_METHOD(bindings, "_defineClass", DefineClass);
  NODE_SET_METHOD(bindings, "eval", Eval);
  NODE_SET_METHOD(bindings, "getMethod", GetMethod);
  // TODO: Maybe we should load the constants here and place them in an object?
  NODE_SET_METHOD(bindings, "getConstant", GetConstant);

  NanReturnValue(bindings);
}

Local<Function> Ruby::GetCtor(Local<Function> rubyClass)
{
  NanEscapableScope();

  Local<Function> getCtor = NanNew<Function>(s_getCtor);
  Handle<Value> argv[] = { rubyClass };
  return NanEscapeScope(NanMakeCallback(NanGetCurrentContext()->Global(),
                                        getCtor, 1, argv).As<Function>());
}

struct ConstGetter
{
  ConstGetter(Handle<Value> nv) : nameVal(nv) {}
  VALUE operator()() const
  {
    NanScope();

    Local<String> constName = nameVal->ToString();
    String::Utf8Value constStr(constName);

    ID id;
    VALUE mod;
    const char* split = std::strstr(*constStr, "::");
    if (split) {
      id = rb_intern(split + 2);
      mod = rb_const_get(rb_cObject, rb_intern2(*constStr, split - *constStr));
    }
    else {
      id = rb_intern2(*constStr, constStr.length());
      mod = rb_cObject;
    }

    return rb_const_get(mod, id);
  }

  Handle<Value> nameVal;
};

// TODO: Should/could we combine this with RubyObject::GetClass?
NAN_METHOD(Ruby::GetClass)
{
  NanScope();

  VALUE klass;
  SAFE_RUBY_CALL(klass, ConstGetter(args[0]));

  if (TYPE(klass) != T_CLASS) {
    std::string msg(*String::Utf8Value(args[0]));
    msg.append(" is not a class");
    NanThrowTypeError(msg.c_str());
    NanReturnUndefined();
  }

  NanReturnValue(RubyObject::GetClass(klass));
}

struct ClassDefiner
{
  ClassDefiner(Handle<Value> nv, VALUE s) : nameVal(nv), super(s) {}
  VALUE operator()() const
  {
    NanScope();

    Local<String> className = nameVal->ToString();
    return rb_define_class(*String::Utf8Value(className), super);
  }

  Handle<Value> nameVal;
  VALUE super;
};

NAN_METHOD(Ruby::DefineClass)
{
  NanScope();

  log("Inherit called for " << *String::Utf8Value(args[0]));

  VALUE super;
  SAFE_RUBY_CALL(super, ConstGetter(args[1]));
  VALUE klass;
  SAFE_RUBY_CALL(klass, ClassDefiner(args[0], super));

  NanReturnValue(RubyObject::GetClass(klass));
}

struct EvalCaller
{
  EvalCaller(const char* s) : str(s) {}
  VALUE operator()() const
  {
    return rb_eval_string(str);
  }

  const char* str;
};

NAN_METHOD(Ruby::Eval)
{
  NanScope();

  Local<String> str = args[0]->ToString();
  VALUE res;
  SAFE_RUBY_CALL(res, EvalCaller(*String::Utf8Value(str)));

  NanReturnValue(rubyToV8(res));
}

NAN_METHOD(CallMethod)
{
  NanScope();
  NanReturnValue(CallRubyFromV8(rb_cObject, args));
}

// TODO: Should this throw immediately if the function doesnt exist?
NAN_METHOD(Ruby::GetMethod)
{
  NanScope();

  Local<String> name = args[0]->ToString();
  ID methodID = rb_intern(*String::Utf8Value(name));
  Local<Function> func =
    NanNew<FunctionTemplate>(CallMethod, EXTERNAL_WRAP((void*)methodID))->GetFunction();
  func->SetName(name);

  NanReturnValue(func);
}

NAN_METHOD(Ruby::GetConstant)
{
  NanScope();

  VALUE constant;
  SAFE_RUBY_CALL(constant, ConstGetter(args[0]));

  // TODO: Should we allow getting classes this way? Maybe throw an exception?
  NanReturnValue(rubyToV8(constant));
}
<|endoftext|>


<commit_before>/**
 * Copyright (c) 2015 - The CM Authors <legal@clickmatcher.com>
 *   All Rights Reserved.
 *
 * This file is CONFIDENTIAL -- Distribution or duplication of this material or
 * the information contained herein is strictly forbidden unless prior written
 * permission is obtained.
 */
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include "fnord-base/io/filerepository.h"
#include "fnord-base/io/fileutil.h"
#include "fnord-base/application.h"
#include "fnord-base/logging.h"
#include "fnord-base/random.h"
#include "fnord-base/thread/eventloop.h"
#include "fnord-base/thread/threadpool.h"
#include "fnord-base/wallclock.h"
#include "fnord-rpc/ServerGroup.h"
#include "fnord-rpc/RPC.h"
#include "fnord-rpc/RPCClient.h"
#include "fnord-base/cli/flagparser.h"
#include "fnord-json/json.h"
#include "fnord-json/jsonrpc.h"
#include "fnord-http/httprouter.h"
#include "fnord-http/httpserver.h"
#include "fnord-feeds/FeedService.h"
#include "fnord-feeds/RemoteFeedFactory.h"
#include "fnord-feeds/RemoteFeedReader.h"
#include "fnord-base/stats/statsdagent.h"
#include "fnord-http/httpconnectionpool.h"
#include "fnord-mdb/MDB.h"
#include <fnord-fts/fts.h>
#include <fnord-fts/fts_common.h>
#include "CustomerNamespace.h"
#include "logjoin/LogJoin.h"
#include "logjoin/LogJoinTarget.h"
#include "logjoin/LogJoinUpload.h"
#include "DocStore.h"
#include "IndexChangeRequest.h"
#include "DocIndex.h"
#include "ItemRef.h"
#include "common.h"
#include "schemas.h"

using namespace cm;
using namespace fnord;

std::atomic<bool> cm_logjoin_shutdown;
fnord::thread::EventLoop ev;

void quit(int n) {
  cm_logjoin_shutdown = true;
}

int main(int argc, const char** argv) {
  fnord::Application::init();
  fnord::Application::logToStderr();

  /* shutdown hook */
  cm_logjoin_shutdown = false;
  struct sigaction sa;
  memset(&sa, 0, sizeof(struct sigaction));
  sa.sa_handler = quit;
  sigaction(SIGTERM, &sa, NULL);
  sigaction(SIGQUIT, &sa, NULL);
  sigaction(SIGINT, &sa, NULL);

  fnord::cli::FlagParser flags;

  flags.defineFlag(
      "conf",
      cli::FlagParser::T_STRING,
      false,
      NULL,
      "./conf",
      "conf directory",
      "<path>");

  flags.defineFlag(
      "datadir",
      cli::FlagParser::T_STRING,
      true,
      NULL,
      NULL,
      "data dir",
      "<path>");

  flags.defineFlag(
      "index",
      cli::FlagParser::T_STRING,
      false,
      NULL,
      NULL,
      "index directory",
      "<path>");

  flags.defineFlag(
      "publish_to",
      fnord::cli::FlagParser::T_STRING,
      true,
      NULL,
      NULL,
      "upload target url",
      "<addr>");

  flags.defineFlag(
      "statsd_addr",
      fnord::cli::FlagParser::T_STRING,
      false,
      NULL,
      "127.0.0.1:8192",
      "Statsd addr",
      "<addr>");

  flags.defineFlag(
      "batch_size",
      fnord::cli::FlagParser::T_INTEGER,
      false,
      NULL,
      "2048",
      "batch_size",
      "<num>");

  flags.defineFlag(
      "buffer_size",
      fnord::cli::FlagParser::T_INTEGER,
      false,
      NULL,
      "8192",
      "buffer_size",
      "<num>");

  flags.defineFlag(
      "flush_interval",
      fnord::cli::FlagParser::T_INTEGER,
      false,
      NULL,
      "5",
      "flush_interval",
      "<num>");

  flags.defineFlag(
      "db_size",
      fnord::cli::FlagParser::T_INTEGER,
      false,
      NULL,
      "128",
      "max sessiondb size",
      "<MB>");

   flags.defineFlag(
      "no_dryrun",
      fnord::cli::FlagParser::T_SWITCH,
      false,
      NULL,
      NULL,
      "no dryrun",
      "<bool>");

  flags.defineFlag(
      "shard",
      fnord::cli::FlagParser::T_STRING,
      false,
      NULL,
      NULL,
      "shard",
      "<name>");

  flags.defineFlag(
      "loglevel",
      fnord::cli::FlagParser::T_STRING,
      false,
      NULL,
      "INFO",
      "loglevel",
      "<level>");

  flags.parseArgv(argc, argv);

  Logger::get()->setMinimumLogLevel(
      strToLogLevel(flags.getString("loglevel")));

  /* schema... */
  auto joined_sessions_schema = joinedSessionsSchema();

  /* start event loop */
  auto evloop_thread = std::thread([] {
    ev.run();
  });

  /* set up rpc client */
  HTTPRPCClient rpc_client(&ev);
  http::HTTPConnectionPool http(&ev);

  /* start stats reporting */
  fnord::stats::StatsdAgent statsd_agent(
      fnord::net::InetAddr::resolve(flags.getString("statsd_addr")),
      10 * fnord::kMicrosPerSecond);

  statsd_agent.start();

  /* get logjoin shard */
  cm::LogJoinShardMap shard_map;
  auto shard = shard_map.getShard(flags.getString("shard"));

  /* set up logjoin */
  auto dry_run = !flags.isSet("no_dryrun");
  size_t batch_size = flags.getInt("batch_size");
  size_t buffer_size = flags.getInt("buffer_size");
  size_t flush_interval = flags.getInt("flush_interval");

  fnord::logInfo(
      "cm.logjoin",
      "Starting cm-logjoin with:\n    dry_run=$0\n    batch_size=$1\n" \
      "    buffer_size=$2\n    flush_interval=$9\n"
      "    max_dbsize=$4MB\n" \
      "    shard=$5\n    shard_range=[$6, $7)\n    shard_modulo=$8",
      dry_run,
      batch_size,
      buffer_size,
      0,
      flags.getInt("db_size"),
      shard.shard_name,
      shard.begin,
      shard.end,
      cm::LogJoinShard::modulo,
      flush_interval);

  fnord::logInfo(
      "cm.logjoin",
      "Using session schema:\n$0",
      joined_sessions_schema.toString());

  /* open session db */
  auto sessdb = mdb::MDB::open(
      flags.getString("datadir"),
      false,
      1000000 * flags.getInt("db_size"),
      shard.shard_name + ".db",
      shard.shard_name + ".db.lck",
      false);

  /* set up input feed reader */
  feeds::RemoteFeedReader feed_reader(&rpc_client);
  feed_reader.setMaxSpread(10 * kMicrosPerSecond);

  HashMap<String, URI> input_feeds;
  input_feeds.emplace(
      "tracker_log.feedserver01.nue01.production.fnrd.net",
      URI("http://s01.nue01.production.fnrd.net:7001/rpc"));
  input_feeds.emplace(
      "tracker_log.feedserver02.nue01.production.fnrd.net",
      URI("http://s02.nue01.production.fnrd.net:7001/rpc"));

  /* setup time backfill */
  feed_reader.setTimeBackfill([] (const feeds::FeedEntry& entry) -> DateTime {
    const auto& log_line = entry.data;

    auto c_end = log_line.find("|");
    if (c_end == std::string::npos) return 0;
    auto t_end = log_line.find("|", c_end + 1);
    if (t_end == std::string::npos) return 0;

    auto timestr = log_line.substr(c_end + 1, t_end - c_end - 1);
    return std::stoul(timestr) * fnord::kMicrosPerSecond;
  });

  /* open index */
  RefPtr<DocIndex> index(
      new DocIndex(
          flags.getString("index"),
          "documents-dawanda",
          true));

  /* set up logjoin target */
  fnord::fts::Analyzer analyzer(flags.getString("conf"));
  cm::LogJoinTarget logjoin_target(
      joined_sessions_schema,
      &analyzer,
      index,
      dry_run);

  /* set up logjoin upload */
  cm::LogJoinUpload logjoin_upload(
      sessdb,
      flags.getString("publish_to"),
      &http);

  /* setup logjoin */
  cm::LogJoin logjoin(shard, dry_run, &logjoin_target);
  logjoin.exportStats("/cm-logjoin/global");
  logjoin.exportStats(StringUtil::format("/cm-logjoin/$0", shard.shard_name));

  fnord::stats::Counter<uint64_t> stat_stream_time_low;
  fnord::stats::Counter<uint64_t> stat_stream_time_high;
  fnord::stats::Counter<uint64_t> stat_active_sessions;
  fnord::stats::Counter<uint64_t> stat_dbsize;

  exportStat(
      StringUtil::format("/cm-logjoin/$0/stream_time_low", shard.shard_name),
      &stat_stream_time_low,
      fnord::stats::ExportMode::EXPORT_VALUE);

  exportStat(
      StringUtil::format("/cm-logjoin/$0/stream_time_high", shard.shard_name),
      &stat_stream_time_high,
      fnord::stats::ExportMode::EXPORT_VALUE);

  exportStat(
      StringUtil::format("/cm-logjoin/$0/active_sessions", shard.shard_name),
      &stat_active_sessions,
      fnord::stats::ExportMode::EXPORT_VALUE);

  exportStat(
      StringUtil::format("/cm-logjoin/$0/dbsize", shard.shard_name),
      &stat_dbsize,
      fnord::stats::ExportMode::EXPORT_VALUE);

  /* upload pending q */
  if (!dry_run) {
    logjoin_upload.upload();
  }

  /* resume from last offset */
  auto txn = sessdb->startTransaction(true);
  try {
    logjoin.importTimeoutList(txn.get());

    for (const auto& input_feed : input_feeds) {
      uint64_t offset = 0;

      auto last_offset = txn->get(
          StringUtil::format("__logjoin_offset~$0", input_feed.first));

      if (!last_offset.isEmpty()) {
        offset = std::stoul(last_offset.get().toString());
      }

      fnord::logInfo(
          "cm.logjoin",
          "Adding source feed:\n    feed=$0\n    url=$1\n    offset: $2",
          input_feed.first,
          input_feed.second.toString(),
          offset);

      feed_reader.addSourceFeed(
          input_feed.second,
          input_feed.first,
          offset,
          batch_size,
          buffer_size);
    }

    txn->abort();
  } catch (...) {
    txn->abort();
    throw;
  }

  fnord::logInfo("cm.logjoin", "Resuming logjoin...");

  DateTime last_flush;
  uint64_t rate_limit_micros = flush_interval * kMicrosPerSecond;

  for (;;) {
    auto begin = WallClock::unixMicros();

    feed_reader.fillBuffers();
    auto txn = sessdb->startTransaction();

    int i = 0;
    for (; i < batch_size; ++i) {
      auto entry = feed_reader.fetchNextEntry();

      if (entry.isEmpty()) {
        break;
      }

      try {
        logjoin.insertLogline(entry.get().data, txn.get());
      } catch (const std::exception& e) {
        fnord::logError("cm.logjoin", e, "invalid log line");
      }
    }

    auto watermarks = feed_reader.watermarks();

    auto etime = WallClock::now().unixMicros() - last_flush.unixMicros();
    if (etime > rate_limit_micros) {
      last_flush = WallClock::now();
      logjoin.flush(txn.get(), watermarks.first);
    }

    auto stream_offsets = feed_reader.streamOffsets();
    String stream_offsets_str;

    for (const auto& soff : stream_offsets) {
      txn->update(
          StringUtil::format("__logjoin_offset~$0", soff.first),
          StringUtil::toString(soff.second));

      stream_offsets_str +=
          StringUtil::format("\n    offset[$0]=$1", soff.first, soff.second);
    }

    fnord::logInfo(
        "cm.logjoin",
        "LogJoin comitting...\n    stream_time=<$0 ... $1>\n" \
        "    active_sessions=$2\n    flushed_sessions=$3$4",
        watermarks.first,
        watermarks.second,
        logjoin.numSessions(),
        logjoin_target.num_sessions,
        stream_offsets_str);

    if (dry_run) {
      txn->abort();
    } else {
      txn->commit();

      try {
        logjoin_upload.upload();
      } catch (const std::exception& e) {
        fnord::logError("cm.logjoin", e, "upload failed");
      }
    }

    if (cm_logjoin_shutdown.load()) {
      break;
    }

    stat_stream_time_low.set(watermarks.first.unixMicros());
    stat_stream_time_high.set(watermarks.second.unixMicros());
    stat_active_sessions.set(logjoin.numSessions());
    //stat_dbsize.set(FileUtil::du_c(flags.getString("datadir"));

    auto rtime = WallClock::unixMicros() - begin;
    auto rlimit = kMicrosPerSecond;
    if (i < 2 && rtime < rlimit) {
      usleep(rlimit - rtime);
    }
  }

  ev.shutdown();
  evloop_thread.join();

  sessdb->sync();
  fnord::logInfo("cm.logjoin", "LogJoin exiting...");
  return 0;
}

<commit_msg>don't read from nue01<commit_after>/**
 * Copyright (c) 2015 - The CM Authors <legal@clickmatcher.com>
 *   All Rights Reserved.
 *
 * This file is CONFIDENTIAL -- Distribution or duplication of this material or
 * the information contained herein is strictly forbidden unless prior written
 * permission is obtained.
 */
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include "fnord-base/io/filerepository.h"
#include "fnord-base/io/fileutil.h"
#include "fnord-base/application.h"
#include "fnord-base/logging.h"
#include "fnord-base/random.h"
#include "fnord-base/thread/eventloop.h"
#include "fnord-base/thread/threadpool.h"
#include "fnord-base/wallclock.h"
#include "fnord-rpc/ServerGroup.h"
#include "fnord-rpc/RPC.h"
#include "fnord-rpc/RPCClient.h"
#include "fnord-base/cli/flagparser.h"
#include "fnord-json/json.h"
#include "fnord-json/jsonrpc.h"
#include "fnord-http/httprouter.h"
#include "fnord-http/httpserver.h"
#include "fnord-feeds/FeedService.h"
#include "fnord-feeds/RemoteFeedFactory.h"
#include "fnord-feeds/RemoteFeedReader.h"
#include "fnord-base/stats/statsdagent.h"
#include "fnord-http/httpconnectionpool.h"
#include "fnord-mdb/MDB.h"
#include <fnord-fts/fts.h>
#include <fnord-fts/fts_common.h>
#include "CustomerNamespace.h"
#include "logjoin/LogJoin.h"
#include "logjoin/LogJoinTarget.h"
#include "logjoin/LogJoinUpload.h"
#include "DocStore.h"
#include "IndexChangeRequest.h"
#include "DocIndex.h"
#include "ItemRef.h"
#include "common.h"
#include "schemas.h"

using namespace cm;
using namespace fnord;

std::atomic<bool> cm_logjoin_shutdown;
fnord::thread::EventLoop ev;

void quit(int n) {
  cm_logjoin_shutdown = true;
}

int main(int argc, const char** argv) {
  fnord::Application::init();
  fnord::Application::logToStderr();

  /* shutdown hook */
  cm_logjoin_shutdown = false;
  struct sigaction sa;
  memset(&sa, 0, sizeof(struct sigaction));
  sa.sa_handler = quit;
  sigaction(SIGTERM, &sa, NULL);
  sigaction(SIGQUIT, &sa, NULL);
  sigaction(SIGINT, &sa, NULL);

  fnord::cli::FlagParser flags;

  flags.defineFlag(
      "conf",
      cli::FlagParser::T_STRING,
      false,
      NULL,
      "./conf",
      "conf directory",
      "<path>");

  flags.defineFlag(
      "datadir",
      cli::FlagParser::T_STRING,
      true,
      NULL,
      NULL,
      "data dir",
      "<path>");

  flags.defineFlag(
      "index",
      cli::FlagParser::T_STRING,
      false,
      NULL,
      NULL,
      "index directory",
      "<path>");

  flags.defineFlag(
      "publish_to",
      fnord::cli::FlagParser::T_STRING,
      true,
      NULL,
      NULL,
      "upload target url",
      "<addr>");

  flags.defineFlag(
      "statsd_addr",
      fnord::cli::FlagParser::T_STRING,
      false,
      NULL,
      "127.0.0.1:8192",
      "Statsd addr",
      "<addr>");

  flags.defineFlag(
      "batch_size",
      fnord::cli::FlagParser::T_INTEGER,
      false,
      NULL,
      "2048",
      "batch_size",
      "<num>");

  flags.defineFlag(
      "buffer_size",
      fnord::cli::FlagParser::T_INTEGER,
      false,
      NULL,
      "8192",
      "buffer_size",
      "<num>");

  flags.defineFlag(
      "flush_interval",
      fnord::cli::FlagParser::T_INTEGER,
      false,
      NULL,
      "5",
      "flush_interval",
      "<num>");

  flags.defineFlag(
      "db_size",
      fnord::cli::FlagParser::T_INTEGER,
      false,
      NULL,
      "128",
      "max sessiondb size",
      "<MB>");

   flags.defineFlag(
      "no_dryrun",
      fnord::cli::FlagParser::T_SWITCH,
      false,
      NULL,
      NULL,
      "no dryrun",
      "<bool>");

  flags.defineFlag(
      "shard",
      fnord::cli::FlagParser::T_STRING,
      false,
      NULL,
      NULL,
      "shard",
      "<name>");

  flags.defineFlag(
      "loglevel",
      fnord::cli::FlagParser::T_STRING,
      false,
      NULL,
      "INFO",
      "loglevel",
      "<level>");

  flags.parseArgv(argc, argv);

  Logger::get()->setMinimumLogLevel(
      strToLogLevel(flags.getString("loglevel")));

  /* schema... */
  auto joined_sessions_schema = joinedSessionsSchema();

  /* start event loop */
  auto evloop_thread = std::thread([] {
    ev.run();
  });

  /* set up rpc client */
  HTTPRPCClient rpc_client(&ev);
  http::HTTPConnectionPool http(&ev);

  /* start stats reporting */
  fnord::stats::StatsdAgent statsd_agent(
      fnord::net::InetAddr::resolve(flags.getString("statsd_addr")),
      10 * fnord::kMicrosPerSecond);

  statsd_agent.start();

  /* get logjoin shard */
  cm::LogJoinShardMap shard_map;
  auto shard = shard_map.getShard(flags.getString("shard"));

  /* set up logjoin */
  auto dry_run = !flags.isSet("no_dryrun");
  size_t batch_size = flags.getInt("batch_size");
  size_t buffer_size = flags.getInt("buffer_size");
  size_t flush_interval = flags.getInt("flush_interval");

  fnord::logInfo(
      "cm.logjoin",
      "Starting cm-logjoin with:\n    dry_run=$0\n    batch_size=$1\n" \
      "    buffer_size=$2\n    flush_interval=$9\n"
      "    max_dbsize=$4MB\n" \
      "    shard=$5\n    shard_range=[$6, $7)\n    shard_modulo=$8",
      dry_run,
      batch_size,
      buffer_size,
      0,
      flags.getInt("db_size"),
      shard.shard_name,
      shard.begin,
      shard.end,
      cm::LogJoinShard::modulo,
      flush_interval);

  fnord::logInfo(
      "cm.logjoin",
      "Using session schema:\n$0",
      joined_sessions_schema.toString());

  /* open session db */
  auto sessdb = mdb::MDB::open(
      flags.getString("datadir"),
      false,
      1000000 * flags.getInt("db_size"),
      shard.shard_name + ".db",
      shard.shard_name + ".db.lck",
      false);

  /* set up input feed reader */
  feeds::RemoteFeedReader feed_reader(&rpc_client);
  feed_reader.setMaxSpread(10 * kMicrosPerSecond);

  HashMap<String, URI> input_feeds;
  //input_feeds.emplace(
  //    "tracker_log.feedserver01.nue01.production.fnrd.net",
  //    URI("http://s01.nue01.production.fnrd.net:7001/rpc"));
  input_feeds.emplace(
      "tracker_log.feedserver02.nue01.production.fnrd.net",
      URI("http://s02.nue01.production.fnrd.net:7001/rpc"));

  /* setup time backfill */
  feed_reader.setTimeBackfill([] (const feeds::FeedEntry& entry) -> DateTime {
    const auto& log_line = entry.data;

    auto c_end = log_line.find("|");
    if (c_end == std::string::npos) return 0;
    auto t_end = log_line.find("|", c_end + 1);
    if (t_end == std::string::npos) return 0;

    auto timestr = log_line.substr(c_end + 1, t_end - c_end - 1);
    return std::stoul(timestr) * fnord::kMicrosPerSecond;
  });

  /* open index */
  RefPtr<DocIndex> index(
      new DocIndex(
          flags.getString("index"),
          "documents-dawanda",
          true));

  /* set up logjoin target */
  fnord::fts::Analyzer analyzer(flags.getString("conf"));
  cm::LogJoinTarget logjoin_target(
      joined_sessions_schema,
      &analyzer,
      index,
      dry_run);

  /* set up logjoin upload */
  cm::LogJoinUpload logjoin_upload(
      sessdb,
      flags.getString("publish_to"),
      &http);

  /* setup logjoin */
  cm::LogJoin logjoin(shard, dry_run, &logjoin_target);
  logjoin.exportStats("/cm-logjoin/global");
  logjoin.exportStats(StringUtil::format("/cm-logjoin/$0", shard.shard_name));

  fnord::stats::Counter<uint64_t> stat_stream_time_low;
  fnord::stats::Counter<uint64_t> stat_stream_time_high;
  fnord::stats::Counter<uint64_t> stat_active_sessions;
  fnord::stats::Counter<uint64_t> stat_dbsize;

  exportStat(
      StringUtil::format("/cm-logjoin/$0/stream_time_low", shard.shard_name),
      &stat_stream_time_low,
      fnord::stats::ExportMode::EXPORT_VALUE);

  exportStat(
      StringUtil::format("/cm-logjoin/$0/stream_time_high", shard.shard_name),
      &stat_stream_time_high,
      fnord::stats::ExportMode::EXPORT_VALUE);

  exportStat(
      StringUtil::format("/cm-logjoin/$0/active_sessions", shard.shard_name),
      &stat_active_sessions,
      fnord::stats::ExportMode::EXPORT_VALUE);

  exportStat(
      StringUtil::format("/cm-logjoin/$0/dbsize", shard.shard_name),
      &stat_dbsize,
      fnord::stats::ExportMode::EXPORT_VALUE);

  /* upload pending q */
  if (!dry_run) {
    logjoin_upload.upload();
  }

  /* resume from last offset */
  auto txn = sessdb->startTransaction(true);
  try {
    logjoin.importTimeoutList(txn.get());

    for (const auto& input_feed : input_feeds) {
      uint64_t offset = 0;

      auto last_offset = txn->get(
          StringUtil::format("__logjoin_offset~$0", input_feed.first));

      if (!last_offset.isEmpty()) {
        offset = std::stoul(last_offset.get().toString());
      }

      fnord::logInfo(
          "cm.logjoin",
          "Adding source feed:\n    feed=$0\n    url=$1\n    offset: $2",
          input_feed.first,
          input_feed.second.toString(),
          offset);

      feed_reader.addSourceFeed(
          input_feed.second,
          input_feed.first,
          offset,
          batch_size,
          buffer_size);
    }

    txn->abort();
  } catch (...) {
    txn->abort();
    throw;
  }

  fnord::logInfo("cm.logjoin", "Resuming logjoin...");

  DateTime last_flush;
  uint64_t rate_limit_micros = flush_interval * kMicrosPerSecond;

  for (;;) {
    auto begin = WallClock::unixMicros();

    feed_reader.fillBuffers();
    auto txn = sessdb->startTransaction();

    int i = 0;
    for (; i < batch_size; ++i) {
      auto entry = feed_reader.fetchNextEntry();

      if (entry.isEmpty()) {
        break;
      }

      try {
        logjoin.insertLogline(entry.get().data, txn.get());
      } catch (const std::exception& e) {
        fnord::logError("cm.logjoin", e, "invalid log line");
      }
    }

    auto watermarks = feed_reader.watermarks();

    auto etime = WallClock::now().unixMicros() - last_flush.unixMicros();
    if (etime > rate_limit_micros) {
      last_flush = WallClock::now();
      logjoin.flush(txn.get(), watermarks.first);
    }

    auto stream_offsets = feed_reader.streamOffsets();
    String stream_offsets_str;

    for (const auto& soff : stream_offsets) {
      txn->update(
          StringUtil::format("__logjoin_offset~$0", soff.first),
          StringUtil::toString(soff.second));

      stream_offsets_str +=
          StringUtil::format("\n    offset[$0]=$1", soff.first, soff.second);
    }

    fnord::logInfo(
        "cm.logjoin",
        "LogJoin comitting...\n    stream_time=<$0 ... $1>\n" \
        "    active_sessions=$2\n    flushed_sessions=$3$4",
        watermarks.first,
        watermarks.second,
        logjoin.numSessions(),
        logjoin_target.num_sessions,
        stream_offsets_str);

    if (dry_run) {
      txn->abort();
    } else {
      txn->commit();

      try {
        logjoin_upload.upload();
      } catch (const std::exception& e) {
        fnord::logError("cm.logjoin", e, "upload failed");
      }
    }

    if (cm_logjoin_shutdown.load()) {
      break;
    }

    stat_stream_time_low.set(watermarks.first.unixMicros());
    stat_stream_time_high.set(watermarks.second.unixMicros());
    stat_active_sessions.set(logjoin.numSessions());
    //stat_dbsize.set(FileUtil::du_c(flags.getString("datadir"));

    auto rtime = WallClock::unixMicros() - begin;
    auto rlimit = kMicrosPerSecond;
    if (i < 2 && rtime < rlimit) {
      usleep(rlimit - rtime);
    }
  }

  ev.shutdown();
  evloop_thread.join();

  sessdb->sync();
  fnord::logInfo("cm.logjoin", "LogJoin exiting...");
  return 0;
}

<|endoftext|>