<commit_before>#include "webcam.hpp"

using namespace cv;
using namespace std;

int main (int argc, char** argv) {

 CvCapture* capture = 0;
 int width, height, fps;

 capture = cvCaptureFromCAM(0);

 if (!capture) {
  printf("No camera detected!");
  return -1;
 }

 ifstream configFile (".config");

 if (configFile.is_open()) {

  //probably want to support corrupted .config
  string line;
  getline(configFile, line);
  istringstream(line)>>width;
  getline(configFile, line);
  istringstream(line)>>height;
  cvSetCaptureProperty(capture, CV_CAP_PROP_FRAME_WIDTH, width);
  cvSetCaptureProperty(capture, CV_CAP_PROP_FRAME_HEIGHT, height);

  configFile.close();

 } else {

  initResolutions();

  for (int i=36; i<150; i++) {
   cvSetCaptureProperty(capture, CV_CAP_PROP_FRAME_WIDTH, resolutions[i].width);
   cvSetCaptureProperty(capture, CV_CAP_PROP_FRAME_HEIGHT, resolutions[i].height);
  }

  width = cvGetCaptureProperty(capture, CV_CAP_PROP_FRAME_WIDTH);
  height = cvGetCaptureProperty(capture, CV_CAP_PROP_FRAME_HEIGHT);

  ofstream configFileOut(".config");
  configFileOut << width;
  configFileOut << "\n";
  configFileOut << height;
  configFileOut << "\n";
  configFileOut.close();
 }

 bool keepGoing = true;

// srand(890);//not interested in good randomness

 Mat image;
 Mat channel[3];

 while (keepGoing) {

  image = cvQueryFrame(capture);
  //imshow("webcam", image);

// thresholds on dark regions

  Mat gray, blurred_gray, threshold_gray;
  cvtColor(image, gray, CV_BGR2GRAY);

  blur(gray, blurred_gray, Size(width/10,height/20));
  equalizeHist(blurred_gray, blurred_gray);
  bitwise_not(blurred_gray, blurred_gray);
  threshold(blurred_gray, threshold_gray, 210, 1, THRESH_BINARY);
//  imshow("threshold", threshold_gray);
// threshold_gray has 1 for probable foreground
// has 0 for idkwtf

  Mat canny;
  Canny(gray, canny, 50, 50, 3);
  blur(canny, canny, Size(width/20,height/20));
  bitwise_not(canny, canny);
  threshold(canny, canny, 220, 1, THRESH_BINARY);
//  imshow("canny", canny);

  Mat certainBackground;
  bitwise_or(canny, threshold_gray, certainBackground);
  Mat kernel = Mat::ones(15, 15, CV_8UC1);
  morphologyEx(certainBackground, certainBackground, MORPH_CLOSE, kernel, Point(-1,-1), 2);
// certainBackground has 0 for definitely not rift
// and 1 for no clue what it is

  Mat bgd, fgd, mask;
  add(threshold_gray, Scalar(2), mask);
  mask = mask.mul(certainBackground);
  imshow("prior mask", mask*80);
  grabCut(image, mask, Rect(0,0,0,0), bgd, fgd, 1, GC_INIT_WITH_MASK);
  imshow("heya", mask*80);

/*
  bitwise_not(gray,gray);
  Mat mask = threshold_gray.mul(gray);
  imshow("mask", mask);

  Moments lol = moments(mask, 1);
  circle(image, Point(lol.m10/lol.m00,lol.m01/lol.m00),20,Scalar(128),30);
  imshow("leimage", image);
*/
  keepGoing = (waitKey(25)<0);

 }

 cvReleaseCapture(&capture);

 return 0;
}
<commit_msg>hacking<commit_after>#include "webcam.hpp"

using namespace cv;
using namespace std;

int main (int argc, char** argv) {

 CvCapture* capture = 0;
 int width, height, fps;

 capture = cvCaptureFromCAM(0);

 if (!capture) {
  printf("No camera detected!");
  return -1;
 }

 ifstream configFile (".config");

 if (configFile.is_open()) {

  //probably want to support corrupted .config
  string line;
  getline(configFile, line);
  istringstream(line)>>width;
  getline(configFile, line);
  istringstream(line)>>height;
  cvSetCaptureProperty(capture, CV_CAP_PROP_FRAME_WIDTH, width);
  cvSetCaptureProperty(capture, CV_CAP_PROP_FRAME_HEIGHT, height);

  configFile.close();

 } else {

  initResolutions();

  for (int i=36; i<150; i++) {
   cvSetCaptureProperty(capture, CV_CAP_PROP_FRAME_WIDTH, resolutions[i].width);
   cvSetCaptureProperty(capture, CV_CAP_PROP_FRAME_HEIGHT, resolutions[i].height);
  }

  width = cvGetCaptureProperty(capture, CV_CAP_PROP_FRAME_WIDTH);
  height = cvGetCaptureProperty(capture, CV_CAP_PROP_FRAME_HEIGHT);

  ofstream configFileOut(".config");
  configFileOut << width;
  configFileOut << "\n";
  configFileOut << height;
  configFileOut << "\n";
  configFileOut.close();
 }

 bool keepGoing = true;

// srand(890);//not interested in good randomness

 Mat image;
 Mat channel[3];

 while (keepGoing) {

  image = cvQueryFrame(capture);
  //imshow("webcam", image);

// thresholds on dark regions

  Mat gray, blurred_gray, threshold_gray;
  cvtColor(image, gray, CV_BGR2GRAY);

  blur(gray, blurred_gray, Size(width/10,height/20));
  equalizeHist(blurred_gray, blurred_gray);
  bitwise_not(blurred_gray, blurred_gray);
  threshold(blurred_gray, threshold_gray, 210, 1, THRESH_BINARY);
//  imshow("threshold", threshold_gray);
// threshold_gray has 1 for probable foreground
// has 0 for idkwtf

  Mat canny;
  Canny(gray, canny, 50, 50, 3);
  blur(canny, canny, Size(width/20,height/20));
  bitwise_not(canny, canny);
  threshold(canny, canny, 220, 1, THRESH_BINARY);
//  imshow("canny", canny);

  Mat certainBackground;
  bitwise_or(canny, threshold_gray, certainBackground);
  Mat kernel = Mat::ones(15, 15, CV_8UC1);
  morphologyEx(certainBackground, certainBackground, MORPH_CLOSE, kernel, Point(-1,-1), 2);
// certainBackground has 0 for definitely not rift
// and 1 for no clue what it is

  Mat bgd, fgd, mask;
  Mat foreground;
  add(threshold_gray, Scalar(2), mask);
  mask = mask.mul(certainBackground);
  bitwise_and(mask, Scalar(1), foreground);
  imshow("FG",foreground.mul(image));
  grabCut(image, mask, Rect(0,0,0,0), bgd, fgd, 1, GC_INIT_WITH_MASK);
  bitwise_and(mask, Scalar(1), foreground);
  imshow("FG2",foreground.mul(image));
  grabCut(image, mask, Rect(0,0,0,0), bgd, fgd, 1, GC_INIT_WITH_MASK);
  bitwise_and(mask, Scalar(1), foreground);
  imshow("FG3",foreground.mul(image));
  grabCut(image, mask, Rect(0,0,0,0), bgd, fgd, 1, GC_INIT_WITH_MASK);
  bitwise_and(mask, Scalar(1), foreground);
  imshow("FG4",foreground.mul(image));

/*
  bitwise_not(gray,gray);
  Mat mask = threshold_gray.mul(gray);
  imshow("mask", mask);

  Moments lol = moments(mask, 1);
  circle(image, Point(lol.m10/lol.m00,lol.m01/lol.m00),20,Scalar(128),30);
  imshow("leimage", image);
*/
  keepGoing = (waitKey(25)<0);

 }

 cvReleaseCapture(&capture);

 return 0;
}
<|endoftext|>


<commit_before>/*****************************************************************************
 * x11_popup.cpp
 *****************************************************************************
 * Copyright (C) 2003 the VideoLAN team
 * $Id$
 *
 * Authors: Olivier Teulire <ipkiss@via.ecp.fr>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
 *****************************************************************************/

#ifdef X11_SKINS

#include "x11_popup.hpp"

X11Popup::X11Popup( intf_thread_t *pIntf, X11Display &rDisplay )
    : OSPopup( pIntf )
{
    // TODO
}

X11Popup::~X11Popup()
{
    // TODO
}

void X11Popup::show( int xPos, int yPos )
{
    // TODO
}

void X11Popup::hide()
{
    // TODO
}

void X11Popup::addItem( const string &rLabel, int pos )
{
    // TODO
}

void X11Popup::addSeparator( int pos )
{
    // TODO
}

int X11Popup::getPosFromId( int id ) const
{
    // TODO
}

#endif

<commit_msg>Compiler warning about a missing return statement in a non-void function.<commit_after>/*****************************************************************************
 * x11_popup.cpp
 *****************************************************************************
 * Copyright (C) 2003 the VideoLAN team
 * $Id$
 *
 * Authors: Olivier Teuli�e <ipkiss@via.ecp.fr>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
 *****************************************************************************/

#ifdef X11_SKINS

#include "x11_popup.hpp"

X11Popup::X11Popup( intf_thread_t *pIntf, X11Display &rDisplay )
    : OSPopup( pIntf )
{
    // TODO
}

X11Popup::~X11Popup()
{
    // TODO
}

void X11Popup::show( int xPos, int yPos )
{
    // TODO
}

void X11Popup::hide()
{
    // TODO
}

void X11Popup::addItem( const string &rLabel, int pos )
{
    // TODO
}

void X11Popup::addSeparator( int pos )
{
    // TODO
}

int X11Popup::getPosFromId( int id ) const
{
    // TODO
    return 0;
}

#endif

<|endoftext|>


<commit_before>#include <tree_sitter/parser.h>
#include <vector>
#include <string>
#include <cctype>

using std::vector;
using std::string;

enum TokenType : TSSymbol {
  SIMPLE_STRING,
  SIMPLE_SYMBOL,
  SIMPLE_SUBSHELL,
  SIMPLE_REGEX,
  SIMPLE_WORD_LIST,
  STRING_BEGINNING,
  SYMBOL_BEGINNING,
  SUBSHELL_BEGINNING,
  REGEX_BEGINNING,
  WORD_LIST_BEGINNING,
  STRING_MIDDLE,
  STRING_END,
  HEREDOC_BEGINNING,
  HEREDOC_END,
  LINE_BREAK
};

struct Literal {
  enum Type {
    STRING,
    SYMBOL,
    SUBSHELL,
    REGEX,
    WORD_LIST
  };

  Type type;
  int32_t open_delimiter;
  int32_t close_delimiter;
  uint32_t nesting_depth;
  bool allows_interpolation;
};

struct Heredoc {
  string word;
  int32_t quote;
};

TokenType BEGINNING_TOKEN_TYPES[] = {
  STRING_BEGINNING,
  SYMBOL_BEGINNING,
  SUBSHELL_BEGINNING,
  REGEX_BEGINNING,
  WORD_LIST_BEGINNING,
};

TokenType SIMPLE_TOKEN_TYPES[] = {
  SIMPLE_STRING,
  SIMPLE_SYMBOL,
  SIMPLE_SUBSHELL,
  SIMPLE_REGEX,
  SIMPLE_WORD_LIST,
};

struct Scanner {
  void skip(TSLexer *lexer) {
    lexer->advance(lexer, true);
  }

  void reset() {}
  bool serialize(TSExternalTokenState state) { return true; }
  void deserialize(TSExternalTokenState state) {}

  void advance(TSLexer *lexer) {
    lexer->advance(lexer, false);
  }

  bool scan_whitespace(TSLexer *lexer, const bool *valid_symbols) {
    for (;;) {
      switch (lexer->lookahead) {
        case ' ':
        case '\t':
          skip(lexer);
          break;
        case '\n':
          if (valid_symbols[LINE_BREAK]) {
            advance(lexer);
            lexer->result_symbol = LINE_BREAK;
            return true;
          } else {
            skip(lexer);
            break;
          }
        default:
          return true;
      }
    }
  }

  bool scan_identifier(TSLexer *lexer) {
    if (lexer->lookahead == '@') {
      advance(lexer);
      if (lexer->lookahead == '@') {
        advance(lexer);
      }
    } else if (lexer->lookahead == '$') {
      advance(lexer);
    }

    if (isalpha(lexer->lookahead)) {
      advance(lexer);
    } else {
      return false;
    }

    while (isalnum(lexer->lookahead) || (lexer->lookahead == '_')) {
      advance(lexer);
    }

    if (lexer->lookahead == '?' || lexer->lookahead == '!') {
      advance(lexer);
    }

    return true;
  }

  bool scan_open_delimiter(TSLexer *lexer, Literal &literal) {
    switch (lexer->lookahead) {
      case '"':
        literal.type = Literal::Type::STRING;
        literal.open_delimiter = literal.close_delimiter = lexer->lookahead;
        literal.nesting_depth = 1;
        literal.allows_interpolation = true;
        advance(lexer);
        return true;

      case '\'':
        literal.type = Literal::Type::STRING;
        literal.open_delimiter = literal.close_delimiter = lexer->lookahead;
        literal.nesting_depth = 1;
        literal.allows_interpolation = false;
        advance(lexer);
        return true;

      case '`':
        literal.type = Literal::Type::SUBSHELL;
        literal.open_delimiter = literal.close_delimiter = lexer->lookahead;
        literal.nesting_depth = 1;
        literal.allows_interpolation = true;
        advance(lexer);
        return true;

      case '/':
        literal.type = Literal::Type::REGEX;
        literal.open_delimiter = literal.close_delimiter = lexer->lookahead;
        literal.nesting_depth = 1;
        literal.allows_interpolation = true;
        advance(lexer);
        return true;

      case '%':
        advance(lexer);

        switch (lexer->lookahead) {
          case 's':
            literal.type = Literal::Type::SYMBOL;
            literal.allows_interpolation = false;
            advance(lexer);
            break;

          case 'r':
            literal.type = Literal::Type::REGEX;
            literal.allows_interpolation = true;
            advance(lexer);
            break;

          case 'x':
            literal.type = Literal::Type::SUBSHELL;
            literal.allows_interpolation = true;
            advance(lexer);
            break;

          case 'q':
            literal.type = Literal::Type::STRING;
            literal.allows_interpolation = false;
            advance(lexer);
            break;

          case 'Q':
            literal.type = Literal::Type::STRING;
            literal.allows_interpolation = true;
            advance(lexer);
            break;

          case 'w':
          case 'i':
            literal.type = Literal::Type::WORD_LIST;
            literal.allows_interpolation = false;
            advance(lexer);
            break;

          case 'W':
          case 'I':
            literal.type = Literal::Type::WORD_LIST;
            literal.allows_interpolation = true;
            advance(lexer);
            break;

          default:
            literal.type = Literal::Type::STRING;
            literal.allows_interpolation = true;
            break;
        }

        switch (lexer->lookahead) {
          case '(':
            literal.open_delimiter = '(';
            literal.close_delimiter = ')';
            literal.nesting_depth = 1;
            break;

          case '[':
            literal.open_delimiter = '[';
            literal.close_delimiter = ']';
            literal.nesting_depth = 1;
            break;

          case '{':
            literal.open_delimiter = '{';
            literal.close_delimiter = '}';
            literal.nesting_depth = 1;
            break;

          case '<':
            literal.open_delimiter = '<';
            literal.close_delimiter = '>';
            literal.nesting_depth = 1;
            break;

          case '|':
          case '!':
          case '#':
          case '/':
          case '\\':
          case '@':
          case '$':
          case '%':
          case '^':
          case '&':
          case '*':
          case ')':
          case ']':
          case '}':
          case '>':
          case '=':
          case '+':
          case '-':
          case '~':
          case '`':
          case ',':
          case '.':
          case '?':
          case ':':
          case ';':
          case '_':
            literal.open_delimiter = lexer->lookahead;
            literal.close_delimiter = lexer->lookahead;
            literal.nesting_depth = 1;
            break;
          default:
            return false;
        }

        advance(lexer);
        return true;

      default:
        return false;
    }
  }

  bool scan_interpolation_close(TSLexer *lexer) {
    if (lexer->lookahead == '}') {
      advance(lexer);
      return true;
    } else {
      return false;
    }
  }

  string scan_heredoc_word(TSLexer *lexer) {
    string result;
    if (isupper(lexer->lookahead)) {
      result += lexer->lookahead;
      advance(lexer);
      while (isupper(lexer->lookahead)) {
        result += lexer->lookahead;
        advance(lexer);
      }
    }
    return result;
  }

  bool scan_heredoc_end(TSLexer *lexer) {
    if (open_heredoc_words.empty()) return false;
    Heredoc heredoc = open_heredoc_words.front();
    open_heredoc_words.erase(open_heredoc_words.begin());
    size_t position_in_word = 0;

    for (;;) {
      for (;;) {
        if (position_in_word == heredoc.word.size() || lexer->lookahead == 0) {
          return true;
        }

        if (lexer->lookahead == heredoc.word[position_in_word]) {
          advance(lexer);
          position_in_word++;
        } else {
          break;
        }
      }

      while (lexer->lookahead != '\n') {
        advance(lexer);
      }

      advance(lexer);
    }

    return true;
  }

  enum ScanContentResult {
    Error,
    Interpolation,
    End
  };

  ScanContentResult scan_content(TSLexer *lexer, Literal &literal) {
    for (;;) {
      if (literal.nesting_depth == 0) {
        if (literal.type == Literal::Type::REGEX) {
          while (islower(lexer->lookahead)) {
            advance(lexer);
          }
        }
        return End;
      }

      if (lexer->lookahead == literal.close_delimiter) {
        literal.nesting_depth--;
        advance(lexer);
      } else if (lexer->lookahead == literal.open_delimiter) {
        literal.nesting_depth++;
        advance(lexer);
      } else if (literal.allows_interpolation && lexer->lookahead == '#') {
        advance(lexer);
        if (lexer->lookahead == '{') {
          advance(lexer);
          return Interpolation;
        }
      } else if (lexer->lookahead == '\\') {
        advance(lexer);
        advance(lexer);
      } else if (lexer->lookahead == 0) {
        advance(lexer);
        return Error;
      } else {
        advance(lexer);
      }
    }
  }

  bool scan(TSLexer *lexer, const bool *valid_symbols) {
    if (!scan_whitespace(lexer, valid_symbols)) return false;
    if (lexer->result_symbol == LINE_BREAK) return true;

    if (valid_symbols[STRING_MIDDLE]) {
      Literal &literal = literal_stack.back();

      if (scan_interpolation_close(lexer)) {
        switch (scan_content(lexer, literal)) {
          case Error:
            return false;
          case Interpolation:
            lexer->result_symbol = STRING_MIDDLE;
            return true;
          case End:
            literal_stack.pop_back();
            lexer->result_symbol = STRING_END;
            return true;
        }
      }
    }

    if (valid_symbols[HEREDOC_END] && !open_heredoc_words.empty()) {
      if (scan_heredoc_end(lexer)) {
        lexer->result_symbol = HEREDOC_END;
        return true;
      }
    }

    if (valid_symbols[SIMPLE_STRING] || valid_symbols[SIMPLE_SYMBOL]) {
      Literal literal;

      if (lexer->lookahead == ':') {
        literal.type = Literal::Type::SYMBOL;
        advance(lexer);

        switch (lexer->lookahead) {
          case '"':
            literal.open_delimiter = '"';
            literal.close_delimiter = '"';
            literal.nesting_depth = 1;
            literal.allows_interpolation = true;
            advance(lexer);
            break;

          case '\'':
            literal.open_delimiter = '\'';
            literal.close_delimiter = '\'';
            literal.nesting_depth = 1;
            literal.allows_interpolation = false;
            advance(lexer);
            break;

          default:
            if (!scan_identifier(lexer)) return false;
            lexer->result_symbol = SIMPLE_SYMBOL;
            return true;
        }
      } else if (lexer->lookahead == '<') {
        advance(lexer);
        if (lexer->lookahead != '<') return false;

        advance(lexer);
        if (lexer->lookahead == '-') advance(lexer);

        Heredoc heredoc;
        literal.allows_interpolation = true;
        switch (lexer->lookahead) {
          case '\'':
            heredoc.quote = '\'';
            literal.allows_interpolation = false;
            advance(lexer);
            break;
          case '"':
            heredoc.quote = '"';
            advance(lexer);
            break;
        }

        heredoc.word = scan_heredoc_word(lexer);
        if (heredoc.word.empty()) return false;

        if(heredoc.quote == lexer->lookahead) advance(lexer);

        open_heredoc_words.push_back(heredoc);
        lexer->result_symbol = HEREDOC_BEGINNING;
        return true;
      } else {
        if (!scan_open_delimiter(lexer, literal)) return false;
      }

      switch (scan_content(lexer, literal)) {
        case Error:
          return false;
        case Interpolation:
          literal_stack.push_back(literal);
          lexer->result_symbol = BEGINNING_TOKEN_TYPES[literal.type];
          return true;
        case End:
          lexer->result_symbol = SIMPLE_TOKEN_TYPES[literal.type];
          return true;
      }
    }

    return false;
  }

  vector<Literal> literal_stack;
  vector<Heredoc> open_heredoc_words;
};

extern "C" {

void *ts_language_ruby_external_scanner_create() {
  return new Scanner();
}

bool ts_language_ruby_external_scanner_scan(void *payload, TSLexer *lexer,
                                            const bool *valid_symbols) {
  Scanner *scanner = static_cast<Scanner *>(payload);
  return scanner->scan(lexer, valid_symbols);
}

void ts_language_ruby_external_scanner_reset(void *payload) {
  Scanner *scanner = static_cast<Scanner *>(payload);
  scanner->reset();
}

bool ts_language_ruby_external_scanner_serialize(void *payload, TSExternalTokenState state) {
  Scanner *scanner = static_cast<Scanner *>(payload);
  return scanner->serialize(state);
}

void ts_language_ruby_external_scanner_deserialize(void *payload, TSExternalTokenState state) {
  Scanner *scanner = static_cast<Scanner *>(payload);
  scanner->deserialize(state);
}

void ts_language_ruby_external_scanner_destroy(void *payload) {
  Scanner *scanner = static_cast<Scanner *>(payload);
  delete scanner;
}

}
<commit_msg>Heredoc word doesn't need to be upper<commit_after>#include <tree_sitter/parser.h>
#include <vector>
#include <string>
#include <cctype>

using std::vector;
using std::string;

enum TokenType : TSSymbol {
  SIMPLE_STRING,
  SIMPLE_SYMBOL,
  SIMPLE_SUBSHELL,
  SIMPLE_REGEX,
  SIMPLE_WORD_LIST,
  STRING_BEGINNING,
  SYMBOL_BEGINNING,
  SUBSHELL_BEGINNING,
  REGEX_BEGINNING,
  WORD_LIST_BEGINNING,
  STRING_MIDDLE,
  STRING_END,
  HEREDOC_BEGINNING,
  HEREDOC_END,
  LINE_BREAK
};

struct Literal {
  enum Type {
    STRING,
    SYMBOL,
    SUBSHELL,
    REGEX,
    WORD_LIST
  };

  Type type;
  int32_t open_delimiter;
  int32_t close_delimiter;
  uint32_t nesting_depth;
  bool allows_interpolation;
};

struct Heredoc {
  string word;
  int32_t quote;
};

TokenType BEGINNING_TOKEN_TYPES[] = {
  STRING_BEGINNING,
  SYMBOL_BEGINNING,
  SUBSHELL_BEGINNING,
  REGEX_BEGINNING,
  WORD_LIST_BEGINNING,
};

TokenType SIMPLE_TOKEN_TYPES[] = {
  SIMPLE_STRING,
  SIMPLE_SYMBOL,
  SIMPLE_SUBSHELL,
  SIMPLE_REGEX,
  SIMPLE_WORD_LIST,
};

struct Scanner {
  void skip(TSLexer *lexer) {
    lexer->advance(lexer, true);
  }

  void reset() {}
  bool serialize(TSExternalTokenState state) { return true; }
  void deserialize(TSExternalTokenState state) {}

  void advance(TSLexer *lexer) {
    lexer->advance(lexer, false);
  }

  bool scan_whitespace(TSLexer *lexer, const bool *valid_symbols) {
    for (;;) {
      switch (lexer->lookahead) {
        case ' ':
        case '\t':
          skip(lexer);
          break;
        case '\n':
          if (valid_symbols[LINE_BREAK]) {
            advance(lexer);
            lexer->result_symbol = LINE_BREAK;
            return true;
          } else {
            skip(lexer);
            break;
          }
        default:
          return true;
      }
    }
  }

  bool scan_identifier(TSLexer *lexer) {
    if (lexer->lookahead == '@') {
      advance(lexer);
      if (lexer->lookahead == '@') {
        advance(lexer);
      }
    } else if (lexer->lookahead == '$') {
      advance(lexer);
    }

    if (isalpha(lexer->lookahead)) {
      advance(lexer);
    } else {
      return false;
    }

    while (isalnum(lexer->lookahead) || (lexer->lookahead == '_')) {
      advance(lexer);
    }

    if (lexer->lookahead == '?' || lexer->lookahead == '!') {
      advance(lexer);
    }

    return true;
  }

  bool scan_open_delimiter(TSLexer *lexer, Literal &literal) {
    switch (lexer->lookahead) {
      case '"':
        literal.type = Literal::Type::STRING;
        literal.open_delimiter = literal.close_delimiter = lexer->lookahead;
        literal.nesting_depth = 1;
        literal.allows_interpolation = true;
        advance(lexer);
        return true;

      case '\'':
        literal.type = Literal::Type::STRING;
        literal.open_delimiter = literal.close_delimiter = lexer->lookahead;
        literal.nesting_depth = 1;
        literal.allows_interpolation = false;
        advance(lexer);
        return true;

      case '`':
        literal.type = Literal::Type::SUBSHELL;
        literal.open_delimiter = literal.close_delimiter = lexer->lookahead;
        literal.nesting_depth = 1;
        literal.allows_interpolation = true;
        advance(lexer);
        return true;

      case '/':
        literal.type = Literal::Type::REGEX;
        literal.open_delimiter = literal.close_delimiter = lexer->lookahead;
        literal.nesting_depth = 1;
        literal.allows_interpolation = true;
        advance(lexer);
        return true;

      case '%':
        advance(lexer);

        switch (lexer->lookahead) {
          case 's':
            literal.type = Literal::Type::SYMBOL;
            literal.allows_interpolation = false;
            advance(lexer);
            break;

          case 'r':
            literal.type = Literal::Type::REGEX;
            literal.allows_interpolation = true;
            advance(lexer);
            break;

          case 'x':
            literal.type = Literal::Type::SUBSHELL;
            literal.allows_interpolation = true;
            advance(lexer);
            break;

          case 'q':
            literal.type = Literal::Type::STRING;
            literal.allows_interpolation = false;
            advance(lexer);
            break;

          case 'Q':
            literal.type = Literal::Type::STRING;
            literal.allows_interpolation = true;
            advance(lexer);
            break;

          case 'w':
          case 'i':
            literal.type = Literal::Type::WORD_LIST;
            literal.allows_interpolation = false;
            advance(lexer);
            break;

          case 'W':
          case 'I':
            literal.type = Literal::Type::WORD_LIST;
            literal.allows_interpolation = true;
            advance(lexer);
            break;

          default:
            literal.type = Literal::Type::STRING;
            literal.allows_interpolation = true;
            break;
        }

        switch (lexer->lookahead) {
          case '(':
            literal.open_delimiter = '(';
            literal.close_delimiter = ')';
            literal.nesting_depth = 1;
            break;

          case '[':
            literal.open_delimiter = '[';
            literal.close_delimiter = ']';
            literal.nesting_depth = 1;
            break;

          case '{':
            literal.open_delimiter = '{';
            literal.close_delimiter = '}';
            literal.nesting_depth = 1;
            break;

          case '<':
            literal.open_delimiter = '<';
            literal.close_delimiter = '>';
            literal.nesting_depth = 1;
            break;

          case '|':
          case '!':
          case '#':
          case '/':
          case '\\':
          case '@':
          case '$':
          case '%':
          case '^':
          case '&':
          case '*':
          case ')':
          case ']':
          case '}':
          case '>':
          case '=':
          case '+':
          case '-':
          case '~':
          case '`':
          case ',':
          case '.':
          case '?':
          case ':':
          case ';':
          case '_':
            literal.open_delimiter = lexer->lookahead;
            literal.close_delimiter = lexer->lookahead;
            literal.nesting_depth = 1;
            break;
          default:
            return false;
        }

        advance(lexer);
        return true;

      default:
        return false;
    }
  }

  bool scan_interpolation_close(TSLexer *lexer) {
    if (lexer->lookahead == '}') {
      advance(lexer);
      return true;
    } else {
      return false;
    }
  }

  string scan_heredoc_word(TSLexer *lexer) {
    string result;
    if (isalpha(lexer->lookahead)) {
      result += lexer->lookahead;
      advance(lexer);
      while (isalpha(lexer->lookahead)) {
        result += lexer->lookahead;
        advance(lexer);
      }
    }
    return result;
  }

  bool scan_heredoc_end(TSLexer *lexer) {
    if (open_heredoc_words.empty()) return false;
    Heredoc heredoc = open_heredoc_words.front();
    open_heredoc_words.erase(open_heredoc_words.begin());
    size_t position_in_word = 0;

    for (;;) {
      for (;;) {
        if (position_in_word == heredoc.word.size() || lexer->lookahead == 0) {
          return true;
        }

        if (lexer->lookahead == heredoc.word[position_in_word]) {
          advance(lexer);
          position_in_word++;
        } else {
          break;
        }
      }

      while (lexer->lookahead != '\n') {
        advance(lexer);
      }

      advance(lexer);
    }

    return true;
  }

  enum ScanContentResult {
    Error,
    Interpolation,
    End
  };

  ScanContentResult scan_content(TSLexer *lexer, Literal &literal) {
    for (;;) {
      if (literal.nesting_depth == 0) {
        if (literal.type == Literal::Type::REGEX) {
          while (islower(lexer->lookahead)) {
            advance(lexer);
          }
        }
        return End;
      }

      if (lexer->lookahead == literal.close_delimiter) {
        literal.nesting_depth--;
        advance(lexer);
      } else if (lexer->lookahead == literal.open_delimiter) {
        literal.nesting_depth++;
        advance(lexer);
      } else if (literal.allows_interpolation && lexer->lookahead == '#') {
        advance(lexer);
        if (lexer->lookahead == '{') {
          advance(lexer);
          return Interpolation;
        }
      } else if (lexer->lookahead == '\\') {
        advance(lexer);
        advance(lexer);
      } else if (lexer->lookahead == 0) {
        advance(lexer);
        return Error;
      } else {
        advance(lexer);
      }
    }
  }

  bool scan(TSLexer *lexer, const bool *valid_symbols) {
    if (!scan_whitespace(lexer, valid_symbols)) return false;
    if (lexer->result_symbol == LINE_BREAK) return true;

    if (valid_symbols[STRING_MIDDLE]) {
      Literal &literal = literal_stack.back();

      if (scan_interpolation_close(lexer)) {
        switch (scan_content(lexer, literal)) {
          case Error:
            return false;
          case Interpolation:
            lexer->result_symbol = STRING_MIDDLE;
            return true;
          case End:
            literal_stack.pop_back();
            lexer->result_symbol = STRING_END;
            return true;
        }
      }
    }

    if (valid_symbols[HEREDOC_END] && !open_heredoc_words.empty()) {
      if (scan_heredoc_end(lexer)) {
        lexer->result_symbol = HEREDOC_END;
        return true;
      }
    }

    if (valid_symbols[SIMPLE_STRING] || valid_symbols[SIMPLE_SYMBOL]) {
      Literal literal;

      if (lexer->lookahead == ':') {
        literal.type = Literal::Type::SYMBOL;
        advance(lexer);

        switch (lexer->lookahead) {
          case '"':
            literal.open_delimiter = '"';
            literal.close_delimiter = '"';
            literal.nesting_depth = 1;
            literal.allows_interpolation = true;
            advance(lexer);
            break;

          case '\'':
            literal.open_delimiter = '\'';
            literal.close_delimiter = '\'';
            literal.nesting_depth = 1;
            literal.allows_interpolation = false;
            advance(lexer);
            break;

          default:
            if (!scan_identifier(lexer)) return false;
            lexer->result_symbol = SIMPLE_SYMBOL;
            return true;
        }
      } else if (lexer->lookahead == '<') {
        advance(lexer);
        if (lexer->lookahead != '<') return false;

        advance(lexer);
        if (lexer->lookahead == '-') advance(lexer);

        Heredoc heredoc;
        literal.allows_interpolation = true;
        switch (lexer->lookahead) {
          case '\'':
            heredoc.quote = '\'';
            literal.allows_interpolation = false;
            advance(lexer);
            break;
          case '"':
            heredoc.quote = '"';
            advance(lexer);
            break;
        }

        heredoc.word = scan_heredoc_word(lexer);
        if (heredoc.word.empty()) return false;

        if(heredoc.quote == lexer->lookahead) advance(lexer);

        open_heredoc_words.push_back(heredoc);
        lexer->result_symbol = HEREDOC_BEGINNING;
        return true;
      } else {
        if (!scan_open_delimiter(lexer, literal)) return false;
      }

      switch (scan_content(lexer, literal)) {
        case Error:
          return false;
        case Interpolation:
          literal_stack.push_back(literal);
          lexer->result_symbol = BEGINNING_TOKEN_TYPES[literal.type];
          return true;
        case End:
          lexer->result_symbol = SIMPLE_TOKEN_TYPES[literal.type];
          return true;
      }
    }

    return false;
  }

  vector<Literal> literal_stack;
  vector<Heredoc> open_heredoc_words;
};

extern "C" {

void *ts_language_ruby_external_scanner_create() {
  return new Scanner();
}

bool ts_language_ruby_external_scanner_scan(void *payload, TSLexer *lexer,
                                            const bool *valid_symbols) {
  Scanner *scanner = static_cast<Scanner *>(payload);
  return scanner->scan(lexer, valid_symbols);
}

void ts_language_ruby_external_scanner_reset(void *payload) {
  Scanner *scanner = static_cast<Scanner *>(payload);
  scanner->reset();
}

bool ts_language_ruby_external_scanner_serialize(void *payload, TSExternalTokenState state) {
  Scanner *scanner = static_cast<Scanner *>(payload);
  return scanner->serialize(state);
}

void ts_language_ruby_external_scanner_deserialize(void *payload, TSExternalTokenState state) {
  Scanner *scanner = static_cast<Scanner *>(payload);
  scanner->deserialize(state);
}

void ts_language_ruby_external_scanner_destroy(void *payload) {
  Scanner *scanner = static_cast<Scanner *>(payload);
  delete scanner;
}

}
<|endoftext|>


<commit_before>// ======================================================================== //
// Copyright 2009-2017 Intel Corporation                                    //
//                                                                          //
// Licensed under the Apache License, Version 2.0 (the "License");          //
// you may not use this file except in compliance with the License.         //
// You may obtain a copy of the License at                                  //
//                                                                          //
//     http://www.apache.org/licenses/LICENSE-2.0                           //
//                                                                          //
// Unless required by applicable law or agreed to in writing, software      //
// distributed under the License is distributed on an "AS IS" BASIS,        //
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. //
// See the License for the specific language governing permissions and      //
// limitations under the License.                                           //
// ======================================================================== //

#undef NDEBUG // do all assertions in this file

//ospray
#include "ospray/camera/Camera.h"
#include "ospray/common/Data.h"
#include "ospray/lights/Light.h"
#include "ospray/transferFunction/TransferFunction.h"
//mpiCommon
#include "mpiCommon/MPICommon.h"
//ospray_mpi
#include "mpi/MPIDistributedDevice.h"
#include "mpi/fb/DistributedFrameBuffer.h"
#include "mpi/render/MPILoadBalancer.h"

//distributed objects
#include "render/distributed/DistributedRaycast.h"

#ifdef OPEN_MPI
# include <thread>
//# define _GNU_SOURCE
# include <sched.h>
#endif

namespace ospray {
  namespace mpi {

    // Helper functions ///////////////////////////////////////////////////////

    template <typename OSPRAY_TYPE, typename API_TYPE>
    inline API_TYPE createOSPRayObjectWithHandle(const char *type)
    {
      auto *instance = OSPRAY_TYPE::createInstance(type);
      instance->refInc();

      ObjectHandle handle;
      handle.assign(instance);

      return (API_TYPE)(int64)handle;
    }

    template <typename OSPRAY_TYPE>
    inline OSPRAY_TYPE& objectFromAPIHandle(OSPObject obj)
    {
      auto &handle = reinterpret_cast<ObjectHandle&>(obj);
      auto *object = (OSPRAY_TYPE*)handle.lookup();

      if (!object)
        throw std::runtime_error("#dmpi: ObjectHandle doesn't exist!");

      return *object;
    }

    static void embreeErrorFunc(const RTCError code, const char* str)
    {
      postStatusMsg() << "#osp: embree internal error " << code << " : " << str;
      throw std::runtime_error("embree internal error '" +std::string(str)+"'");
    }

    // MPIDistributedDevice definitions ///////////////////////////////////////

    MPIDistributedDevice::~MPIDistributedDevice()
    {
      try {
        MPI_CALL(Finalize());
      } catch (...) {
        //TODO: anything to do here? try-catch added to silence a warning...
      }
    }

    void MPIDistributedDevice::commit()
    {
      if (!initialized) {
        int _ac = 1;
        const char *_av[] = {"ospray_mpi_worker"};

        mpicommon::init(&_ac, _av);

        std::stringstream embreeConfig;
        if (debugMode)
          embreeConfig << " threads=1,verbose=2";
        else if(numThreads > 0)
          embreeConfig << " threads=" << numThreads;
        embreeDevice = rtcNewDevice(embreeConfig.str().c_str());

        rtcDeviceSetErrorFunction(embreeDevice, embreeErrorFunc);

        RTCError erc = rtcDeviceGetError(embreeDevice);
        if (erc != RTC_NO_ERROR) {
          // why did the error function not get called !?
          postStatusMsg() << "#osp:init: embree internal error number " << erc;
          assert(erc == RTC_NO_ERROR);
        }

        initialized = true;
      }

      Device::commit();

      masterRank = getParam1i("masterRank", 0);

      std::string mode = getParamString("mode", "distributed");

      if (mode == "distributed") {
        postStatusMsg() << "#dmpi: device commit() setting mode to " << mode;
      } else {
        throw std::runtime_error("#dmpi: bad device mode ['" + mode + "]");
      }

      // TODO: implement 'staticLoadBalancer::Distributed'
      //TiledLoadBalancer::instance = make_unique<staticLoadBalancer::Master>();
    }

    OSPFrameBuffer
    MPIDistributedDevice::frameBufferCreate(const vec2i &size,
                                            const OSPFrameBufferFormat mode,
                                            const uint32 channels)
    {
      const bool hasDepthBuffer    = channels & OSP_FB_DEPTH;
      const bool hasAccumBuffer    = channels & OSP_FB_ACCUM;
      const bool hasVarianceBuffer = channels & OSP_FB_VARIANCE;

      ObjectHandle handle;

      auto *instance = new DistributedFrameBuffer(size, handle, mode,
                                                  hasDepthBuffer,
                                                  hasAccumBuffer,
                                                  hasVarianceBuffer,
                                                  true);
      instance->refInc();

      handle.assign(instance);

      return (OSPFrameBuffer)(int64)handle;
    }

    const void*
    MPIDistributedDevice::frameBufferMap(OSPFrameBuffer _fb,
                                         OSPFrameBufferChannel channel)
    {
      if (!mpicommon::IamTheMaster())
        throw std::runtime_error("Can only map framebuffer on the master!");

      auto &fb = objectFromAPIHandle<FrameBuffer>(_fb);

      switch (channel) {
      case OSP_FB_COLOR: return fb.mapColorBuffer();
      case OSP_FB_DEPTH: return fb.mapDepthBuffer();
      default: return nullptr;
      }
    }

    void MPIDistributedDevice::frameBufferUnmap(const void *mapped,
                                                OSPFrameBuffer _fb)
    {
      auto &fb = objectFromAPIHandle<FrameBuffer>(_fb);
      fb.unmap(mapped);
    }

    void MPIDistributedDevice::frameBufferClear(OSPFrameBuffer _fb,
                                                const uint32 fbChannelFlags)
    {
      auto &fb = objectFromAPIHandle<FrameBuffer>(_fb);
      fb.clear(fbChannelFlags);
    }

    OSPModel MPIDistributedDevice::newModel()
    {
      auto *instance = new Model;
      instance->refInc();

      ObjectHandle handle;
      handle.assign(instance);

      return (OSPModel)(int64)handle;
    }

    void MPIDistributedDevice::commit(OSPObject _object)
    {
      auto &object = objectFromAPIHandle<ManagedObject>(_object);
      object.commit();
    }

    void MPIDistributedDevice::addGeometry(OSPModel _model,
                                           OSPGeometry _geometry)
    {
      auto &model = objectFromAPIHandle<Model>(_model);
      auto &geom  = objectFromAPIHandle<Geometry>(_geometry);

      model.geometry.push_back(&geom);
    }

    void MPIDistributedDevice::addVolume(OSPModel _model, OSPVolume _volume)
    {
      NOT_IMPLEMENTED;
    }

    OSPData MPIDistributedDevice::newData(size_t nitems, OSPDataType format,
                                          void *init, int flags)
    {
      ObjectHandle handle;

      auto *instance = new Data(nitems, format, init, flags);
      instance->refInc();

      handle.assign(instance);

      return (OSPData)(int64)handle;
    }

    void MPIDistributedDevice::setVoidPtr(OSPObject _object,
                                          const char *bufName,
                                          void *v)
    {
      auto &object = objectFromAPIHandle<ManagedObject>(_object);
      object.findParam(bufName, true)->set(v);
    }

    void MPIDistributedDevice::removeParam(OSPObject _object, const char *name)
    {
      auto &object = objectFromAPIHandle<ManagedObject>(_object);
      object.removeParam(name);
    }

    int MPIDistributedDevice::setRegion(OSPVolume _volume, const void *source,
                                        const vec3i &index, const vec3i &count)
    {
      NOT_IMPLEMENTED;
    }

    void MPIDistributedDevice::setString(OSPObject _object,
                                         const char *bufName,
                                         const char *s)
    {
      auto &object = objectFromAPIHandle<ManagedObject>(_object);
      object.findParam(bufName, true)->set(s);
    }

    int MPIDistributedDevice::loadModule(const char *name)
    {
      return loadLocalModule(name);
    }

    void MPIDistributedDevice::setFloat(OSPObject _object,
                                        const char *bufName,
                                        const float f)
    {
      auto &object = objectFromAPIHandle<ManagedObject>(_object);
      object.findParam(bufName, true)->set(f);
    }

    void MPIDistributedDevice::setInt(OSPObject _object,
                                      const char *bufName,
                                      const int i)
    {
      auto &object = objectFromAPIHandle<ManagedObject>(_object);
      object.findParam(bufName, true)->set(i);
    }

    void MPIDistributedDevice::setVec2f(OSPObject _object,
                                        const char *bufName,
                                        const vec2f &v)
    {
      auto &object = objectFromAPIHandle<ManagedObject>(_object);
      object.findParam(bufName, true)->set(v);
    }

    void MPIDistributedDevice::setVec3f(OSPObject _object,
                                        const char *bufName,
                                        const vec3f &v)
    {
      auto &object = objectFromAPIHandle<ManagedObject>(_object);
      object.findParam(bufName, true)->set(v);
    }

    void MPIDistributedDevice::setVec4f(OSPObject _object,
                                        const char *bufName,
                                        const vec4f &v)
    {
      auto &object = objectFromAPIHandle<ManagedObject>(_object);
      object.findParam(bufName, true)->set(v);
    }

    void MPIDistributedDevice::setVec2i(OSPObject _object,
                                        const char *bufName,
                                        const vec2i &v)
    {
      auto &object = objectFromAPIHandle<ManagedObject>(_object);
      object.findParam(bufName, true)->set(v);
    }

    void MPIDistributedDevice::setVec3i(OSPObject _object,
                                        const char *bufName,
                                        const vec3i &v)
    {
      auto &object = objectFromAPIHandle<ManagedObject>(_object);
      object.findParam(bufName, true)->set(v);
    }

    void MPIDistributedDevice::setObject(OSPObject _object,
                                         const char *bufName,
                                         OSPObject _value)
    {
      auto &object = objectFromAPIHandle<ManagedObject>(_object);
      auto &value  = objectFromAPIHandle<ManagedObject>(_value);
      object.set(bufName, &value);
    }

    OSPPixelOp MPIDistributedDevice::newPixelOp(const char *type)
    {
      NOT_IMPLEMENTED;
    }

    void MPIDistributedDevice::setPixelOp(OSPFrameBuffer _fb, OSPPixelOp _op)
    {
      NOT_IMPLEMENTED;
    }

    OSPRenderer MPIDistributedDevice::newRenderer(const char *type)
    {
      UNUSED(type);
      auto *instance = new DistributedRaycastRenderer;

      ObjectHandle handle;
      handle.assign(instance);

      return (OSPRenderer)(int64)handle;
    }

    OSPCamera MPIDistributedDevice::newCamera(const char *type)
    {
      return createOSPRayObjectWithHandle<Camera, OSPCamera>(type);
    }

    OSPVolume MPIDistributedDevice::newVolume(const char *type)
    {
      NOT_IMPLEMENTED;
    }

    OSPGeometry MPIDistributedDevice::newGeometry(const char *type)
    {
      return createOSPRayObjectWithHandle<Geometry, OSPGeometry>(type);
    }

    OSPMaterial MPIDistributedDevice::newMaterial(OSPRenderer _renderer,
                                                  const char *type)
    {
      NOT_IMPLEMENTED;
    }

    OSPTransferFunction
    MPIDistributedDevice::newTransferFunction(const char *type)
    {
      return createOSPRayObjectWithHandle<TransferFunction,
                                          OSPTransferFunction>(type);
    }

    OSPLight MPIDistributedDevice::newLight(OSPRenderer _renderer,
                                            const char *type)
    {
      auto &renderer = objectFromAPIHandle<Renderer>(_renderer);
      auto *light    = renderer.createLight(type);

      if (light == nullptr)
        light = Light::createLight(type);

      if (light) {
        ObjectHandle handle;

        handle.assign(light);

        return (OSPLight)(int64)handle;
      } else {
        return nullptr;
      }
    }

    void MPIDistributedDevice::removeGeometry(OSPModel _model,
                                              OSPGeometry _geometry)
    {
      auto model = objectFromAPIHandle<Model>(_model);
      auto geom  = objectFromAPIHandle<Geometry>(_geometry);

      //TODO: confirm this works?
      model.geometry.erase(std::remove(model.geometry.begin(),
                                       model.geometry.end(),
                                       Ref<Geometry>(&geom)));
    }

    void MPIDistributedDevice::removeVolume(OSPModel _model, OSPVolume _volume)
    {
      NOT_IMPLEMENTED;
    }

    float MPIDistributedDevice::renderFrame(OSPFrameBuffer _fb,
                                            OSPRenderer _renderer,
                                            const uint32 fbChannelFlags)
    {
      auto &fb       = objectFromAPIHandle<FrameBuffer>(_fb);
      auto &renderer = objectFromAPIHandle<Renderer>(_renderer);
      auto result    = renderer.renderFrame(&fb, fbChannelFlags);
      mpicommon::world.barrier();
      return result;
    }

    void MPIDistributedDevice::release(OSPObject _obj)
    {
      UNUSED(_obj);
      postStatusMsg(1) << "WARNING: release() not implemented, memory leak!";
    }

    void MPIDistributedDevice::setMaterial(OSPGeometry _geometry,
                                           OSPMaterial _material)
    {
      NOT_IMPLEMENTED;
    }

    OSPTexture2D MPIDistributedDevice::newTexture2D(
      const vec2i &sz,
      const OSPTextureFormat type,
      void *data,
      const uint32 flags
    )
    {
      NOT_IMPLEMENTED;
    }

    void MPIDistributedDevice::sampleVolume(float **results,
                                            OSPVolume volume,
                                            const vec3f *worldCoordinates,
                                            const size_t &count)
    {
      NOT_IMPLEMENTED;
    }

    OSP_REGISTER_DEVICE(MPIDistributedDevice, mpi_distributed_device);
    OSP_REGISTER_DEVICE(MPIDistributedDevice, mpi_distributed);

  } // ::ospray::mpi
} // ::ospray
<commit_msg>MPIDistributedDevice now can accept volumes (no support in renderer yet)<commit_after>// ======================================================================== //
// Copyright 2009-2017 Intel Corporation                                    //
//                                                                          //
// Licensed under the Apache License, Version 2.0 (the "License");          //
// you may not use this file except in compliance with the License.         //
// You may obtain a copy of the License at                                  //
//                                                                          //
//     http://www.apache.org/licenses/LICENSE-2.0                           //
//                                                                          //
// Unless required by applicable law or agreed to in writing, software      //
// distributed under the License is distributed on an "AS IS" BASIS,        //
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. //
// See the License for the specific language governing permissions and      //
// limitations under the License.                                           //
// ======================================================================== //

#undef NDEBUG // do all assertions in this file

//ospray
#include "ospray/camera/Camera.h"
#include "ospray/common/Data.h"
#include "ospray/lights/Light.h"
#include "ospray/transferFunction/TransferFunction.h"
//mpiCommon
#include "mpiCommon/MPICommon.h"
//ospray_mpi
#include "mpi/MPIDistributedDevice.h"
#include "mpi/fb/DistributedFrameBuffer.h"
#include "mpi/render/MPILoadBalancer.h"

//distributed objects
#include "render/distributed/DistributedRaycast.h"

#ifdef OPEN_MPI
# include <thread>
//# define _GNU_SOURCE
# include <sched.h>
#endif

namespace ospray {
  namespace mpi {

    // Helper functions ///////////////////////////////////////////////////////

    template <typename OSPRAY_TYPE, typename API_TYPE>
    inline API_TYPE createOSPRayObjectWithHandle(const char *type)
    {
      auto *instance = OSPRAY_TYPE::createInstance(type);
      instance->refInc();

      ObjectHandle handle;
      handle.assign(instance);

      return (API_TYPE)(int64)handle;
    }

    template <typename OSPRAY_TYPE>
    inline OSPRAY_TYPE& objectFromAPIHandle(OSPObject obj)
    {
      auto &handle = reinterpret_cast<ObjectHandle&>(obj);
      auto *object = (OSPRAY_TYPE*)handle.lookup();

      if (!object)
        throw std::runtime_error("#dmpi: ObjectHandle doesn't exist!");

      return *object;
    }

    static void embreeErrorFunc(const RTCError code, const char* str)
    {
      postStatusMsg() << "#osp: embree internal error " << code << " : " << str;
      throw std::runtime_error("embree internal error '" +std::string(str)+"'");
    }

    // MPIDistributedDevice definitions ///////////////////////////////////////

    MPIDistributedDevice::~MPIDistributedDevice()
    {
      try {
        MPI_CALL(Finalize());
      } catch (...) {
        //TODO: anything to do here? try-catch added to silence a warning...
      }
    }

    void MPIDistributedDevice::commit()
    {
      if (!initialized) {
        int _ac = 1;
        const char *_av[] = {"ospray_mpi_worker"};

        mpicommon::init(&_ac, _av);

        std::stringstream embreeConfig;
        if (debugMode)
          embreeConfig << " threads=1,verbose=2";
        else if(numThreads > 0)
          embreeConfig << " threads=" << numThreads;
        embreeDevice = rtcNewDevice(embreeConfig.str().c_str());

        rtcDeviceSetErrorFunction(embreeDevice, embreeErrorFunc);

        RTCError erc = rtcDeviceGetError(embreeDevice);
        if (erc != RTC_NO_ERROR) {
          // why did the error function not get called !?
          postStatusMsg() << "#osp:init: embree internal error number " << erc;
          assert(erc == RTC_NO_ERROR);
        }

        initialized = true;
      }

      Device::commit();

      masterRank = getParam1i("masterRank", 0);

      std::string mode = getParamString("mode", "distributed");

      if (mode == "distributed") {
        postStatusMsg() << "#dmpi: device commit() setting mode to " << mode;
      } else {
        throw std::runtime_error("#dmpi: bad device mode ['" + mode + "]");
      }

      // TODO: implement 'staticLoadBalancer::Distributed'
      //TiledLoadBalancer::instance = make_unique<staticLoadBalancer::Master>();
    }

    OSPFrameBuffer
    MPIDistributedDevice::frameBufferCreate(const vec2i &size,
                                            const OSPFrameBufferFormat mode,
                                            const uint32 channels)
    {
      const bool hasDepthBuffer    = channels & OSP_FB_DEPTH;
      const bool hasAccumBuffer    = channels & OSP_FB_ACCUM;
      const bool hasVarianceBuffer = channels & OSP_FB_VARIANCE;

      ObjectHandle handle;

      auto *instance = new DistributedFrameBuffer(size, handle, mode,
                                                  hasDepthBuffer,
                                                  hasAccumBuffer,
                                                  hasVarianceBuffer,
                                                  true);
      instance->refInc();

      handle.assign(instance);

      return (OSPFrameBuffer)(int64)handle;
    }

    const void*
    MPIDistributedDevice::frameBufferMap(OSPFrameBuffer _fb,
                                         OSPFrameBufferChannel channel)
    {
      if (!mpicommon::IamTheMaster())
        throw std::runtime_error("Can only map framebuffer on the master!");

      auto &fb = objectFromAPIHandle<FrameBuffer>(_fb);

      switch (channel) {
      case OSP_FB_COLOR: return fb.mapColorBuffer();
      case OSP_FB_DEPTH: return fb.mapDepthBuffer();
      default: return nullptr;
      }
    }

    void MPIDistributedDevice::frameBufferUnmap(const void *mapped,
                                                OSPFrameBuffer _fb)
    {
      auto &fb = objectFromAPIHandle<FrameBuffer>(_fb);
      fb.unmap(mapped);
    }

    void MPIDistributedDevice::frameBufferClear(OSPFrameBuffer _fb,
                                                const uint32 fbChannelFlags)
    {
      auto &fb = objectFromAPIHandle<FrameBuffer>(_fb);
      fb.clear(fbChannelFlags);
    }

    OSPModel MPIDistributedDevice::newModel()
    {
      auto *instance = new Model;
      instance->refInc();

      ObjectHandle handle;
      handle.assign(instance);

      return (OSPModel)(int64)handle;
    }

    void MPIDistributedDevice::commit(OSPObject _object)
    {
      auto &object = objectFromAPIHandle<ManagedObject>(_object);
      object.commit();
    }

    void MPIDistributedDevice::addGeometry(OSPModel _model,
                                           OSPGeometry _geometry)
    {
      auto &model = objectFromAPIHandle<Model>(_model);
      auto &geom  = objectFromAPIHandle<Geometry>(_geometry);

      model.geometry.push_back(&geom);
    }

    void MPIDistributedDevice::addVolume(OSPModel _model, OSPVolume _volume)
    {
      auto &model  = objectFromAPIHandle<Model>(_model);
      auto &volume = objectFromAPIHandle<Volume>(_volume);

      model.volume.push_back(&volume);
    }

    OSPData MPIDistributedDevice::newData(size_t nitems, OSPDataType format,
                                          void *init, int flags)
    {
      ObjectHandle handle;

      auto *instance = new Data(nitems, format, init, flags);
      instance->refInc();

      handle.assign(instance);

      return (OSPData)(int64)handle;
    }

    void MPIDistributedDevice::setVoidPtr(OSPObject _object,
                                          const char *bufName,
                                          void *v)
    {
      auto &object = objectFromAPIHandle<ManagedObject>(_object);
      object.findParam(bufName, true)->set(v);
    }

    void MPIDistributedDevice::removeParam(OSPObject _object, const char *name)
    {
      auto &object = objectFromAPIHandle<ManagedObject>(_object);
      object.removeParam(name);
    }

    int MPIDistributedDevice::setRegion(OSPVolume _volume, const void *source,
                                        const vec3i &index, const vec3i &count)
    {
      auto &volume = objectFromAPIHandle<Volume>(_volume);
      volume.setRegion(source, index, count);
    }

    void MPIDistributedDevice::setString(OSPObject _object,
                                         const char *bufName,
                                         const char *s)
    {
      auto &object = objectFromAPIHandle<ManagedObject>(_object);
      object.findParam(bufName, true)->set(s);
    }

    int MPIDistributedDevice::loadModule(const char *name)
    {
      return loadLocalModule(name);
    }

    void MPIDistributedDevice::setFloat(OSPObject _object,
                                        const char *bufName,
                                        const float f)
    {
      auto &object = objectFromAPIHandle<ManagedObject>(_object);
      object.findParam(bufName, true)->set(f);
    }

    void MPIDistributedDevice::setInt(OSPObject _object,
                                      const char *bufName,
                                      const int i)
    {
      auto &object = objectFromAPIHandle<ManagedObject>(_object);
      object.findParam(bufName, true)->set(i);
    }

    void MPIDistributedDevice::setVec2f(OSPObject _object,
                                        const char *bufName,
                                        const vec2f &v)
    {
      auto &object = objectFromAPIHandle<ManagedObject>(_object);
      object.findParam(bufName, true)->set(v);
    }

    void MPIDistributedDevice::setVec3f(OSPObject _object,
                                        const char *bufName,
                                        const vec3f &v)
    {
      auto &object = objectFromAPIHandle<ManagedObject>(_object);
      object.findParam(bufName, true)->set(v);
    }

    void MPIDistributedDevice::setVec4f(OSPObject _object,
                                        const char *bufName,
                                        const vec4f &v)
    {
      auto &object = objectFromAPIHandle<ManagedObject>(_object);
      object.findParam(bufName, true)->set(v);
    }

    void MPIDistributedDevice::setVec2i(OSPObject _object,
                                        const char *bufName,
                                        const vec2i &v)
    {
      auto &object = objectFromAPIHandle<ManagedObject>(_object);
      object.findParam(bufName, true)->set(v);
    }

    void MPIDistributedDevice::setVec3i(OSPObject _object,
                                        const char *bufName,
                                        const vec3i &v)
    {
      auto &object = objectFromAPIHandle<ManagedObject>(_object);
      object.findParam(bufName, true)->set(v);
    }

    void MPIDistributedDevice::setObject(OSPObject _object,
                                         const char *bufName,
                                         OSPObject _value)
    {
      auto &object = objectFromAPIHandle<ManagedObject>(_object);
      auto &value  = objectFromAPIHandle<ManagedObject>(_value);
      object.set(bufName, &value);
    }

    OSPPixelOp MPIDistributedDevice::newPixelOp(const char *type)
    {
      NOT_IMPLEMENTED;
    }

    void MPIDistributedDevice::setPixelOp(OSPFrameBuffer _fb, OSPPixelOp _op)
    {
      NOT_IMPLEMENTED;
    }

    OSPRenderer MPIDistributedDevice::newRenderer(const char *type)
    {
      UNUSED(type);
      auto *instance = new DistributedRaycastRenderer;

      ObjectHandle handle;
      handle.assign(instance);

      return (OSPRenderer)(int64)handle;
    }

    OSPCamera MPIDistributedDevice::newCamera(const char *type)
    {
      return createOSPRayObjectWithHandle<Camera, OSPCamera>(type);
    }

    OSPVolume MPIDistributedDevice::newVolume(const char *type)
    {
      return createOSPRayObjectWithHandle<Volume, OSPVolume>(type);
    }

    OSPGeometry MPIDistributedDevice::newGeometry(const char *type)
    {
      return createOSPRayObjectWithHandle<Geometry, OSPGeometry>(type);
    }

    OSPMaterial MPIDistributedDevice::newMaterial(OSPRenderer _renderer,
                                                  const char *type)
    {
      NOT_IMPLEMENTED;
    }

    OSPTransferFunction
    MPIDistributedDevice::newTransferFunction(const char *type)
    {
      return createOSPRayObjectWithHandle<TransferFunction,
                                          OSPTransferFunction>(type);
    }

    OSPLight MPIDistributedDevice::newLight(OSPRenderer _renderer,
                                            const char *type)
    {
      auto &renderer = objectFromAPIHandle<Renderer>(_renderer);
      auto *light    = renderer.createLight(type);

      if (light == nullptr)
        light = Light::createLight(type);

      if (light) {
        ObjectHandle handle;

        handle.assign(light);

        return (OSPLight)(int64)handle;
      } else {
        return nullptr;
      }
    }

    void MPIDistributedDevice::removeGeometry(OSPModel _model,
                                              OSPGeometry _geometry)
    {
      auto &model = objectFromAPIHandle<Model>(_model);
      auto &geom  = objectFromAPIHandle<Geometry>(_geometry);

      //TODO: confirm this works?
      model.geometry.erase(std::remove(model.geometry.begin(),
                                       model.geometry.end(),
                                       Ref<Geometry>(&geom)));
    }

    void MPIDistributedDevice::removeVolume(OSPModel _model, OSPVolume _volume)
    {
      auto &model  = objectFromAPIHandle<Model>(_model);
      auto &volume = objectFromAPIHandle<Volume>(_volume);

      //TODO: confirm this works?
      model.volume.erase(std::remove(model.volume.begin(),
                                     model.volume.end(),
                                     Ref<Volume>(&volume)));
    }

    float MPIDistributedDevice::renderFrame(OSPFrameBuffer _fb,
                                            OSPRenderer _renderer,
                                            const uint32 fbChannelFlags)
    {
      auto &fb       = objectFromAPIHandle<FrameBuffer>(_fb);
      auto &renderer = objectFromAPIHandle<Renderer>(_renderer);
      auto result    = renderer.renderFrame(&fb, fbChannelFlags);
      mpicommon::world.barrier();
      return result;
    }

    void MPIDistributedDevice::release(OSPObject _obj)
    {
      UNUSED(_obj);
      postStatusMsg(1) << "WARNING: release() not implemented, memory leak!";
    }

    void MPIDistributedDevice::setMaterial(OSPGeometry _geometry,
                                           OSPMaterial _material)
    {
      NOT_IMPLEMENTED;
    }

    OSPTexture2D MPIDistributedDevice::newTexture2D(
      const vec2i &sz,
      const OSPTextureFormat type,
      void *data,
      const uint32 flags
    )
    {
      NOT_IMPLEMENTED;
    }

    void MPIDistributedDevice::sampleVolume(float **results,
                                            OSPVolume volume,
                                            const vec3f *worldCoordinates,
                                            const size_t &count)
    {
      NOT_IMPLEMENTED;
    }

    OSP_REGISTER_DEVICE(MPIDistributedDevice, mpi_distributed_device);
    OSP_REGISTER_DEVICE(MPIDistributedDevice, mpi_distributed);

  } // ::ospray::mpi
} // ::ospray
<|endoftext|>


<commit_before>#include "iotsa.h"
#include "iotsaCapabilities.h"
#include "iotsaConfigFile.h"
#include <ArduinoJWT.h>
#include <ArduinoJson.h>

#define IFDEBUGX if(1)

// Static method to check whether a string exactly matches a Json object,
// or is included in the Json object if it is an array.
static bool stringContainedIn(const char *wanted, JsonVariant& got) {
  if (got.is<char*>()) {
    return strcmp(wanted, got.as<const char *>()) == 0;
  }
  if (!got.is<JsonArray>()) {
    return false;
  }
  JsonArray& gotArray = got.as<JsonArray>();
  for(size_t i=0; i<gotArray.size(); i++) {
    const char *gotItem = gotArray[i];
    if (strcmp(gotItem, wanted) == 0) {
      return true;
    }
  }
  return false;
}

// Get a scope indicator from a JSON variant
static IotsaCapabilityObjectScope getRightFrom(const JsonVariant& arg) {
  if (!arg.is<char*>()) return IOTSA_SCOPE_NONE;
  const char *argStr = arg.as<char*>();
  if (strcmp(argStr, "self") == 0) return IOTSA_SCOPE_SELF;
  if (strcmp(argStr, "descendent-or-self") == 0) return IOTSA_SCOPE_FULL;
  if (strcmp(argStr, "descendent") == 0) return IOTSA_SCOPE_CHILD;
  if (strcmp(argStr, "child") == 0) return IOTSA_SCOPE_CHILD;
  return IOTSA_SCOPE_NONE;
}

bool IotsaCapability::allows(const char *_obj, IotsaApiOperation verb) {
  IotsaCapabilityObjectScope scope = scopes[int(verb)];
  int matchLength = obj.length();
  switch(scope) {
    case IOTSA_SCOPE_NONE:
      break;
    case IOTSA_SCOPE_SELF:
      if (strcmp(obj.c_str(), _obj) == 0)
        return true;
      break;
    case IOTSA_SCOPE_FULL:
      if (strncmp(obj.c_str(), _obj, matchLength) == 0) {
        char nextCh = _obj[matchLength];
        if (nextCh == '\0' || nextCh == '/')
          return true;
      }
      break;
    case IOTSA_SCOPE_CHILD:
      if (strncmp(obj.c_str(), _obj, matchLength) == 0) {
        char nextCh = _obj[matchLength];
        if (nextCh == '/')
          return true;
      }
      break;
  }
  // See if there is a next capabiliy we can check, otherwise we don't have permission.
  if (next) return next->allows(_obj, verb);
  return false;
}

IotsaCapabilityMod::IotsaCapabilityMod(IotsaApplication &_app, IotsaAuthenticationProvider& _chain)
:	IotsaAuthMod(_app),
  capabilities(NULL),
#ifdef IOTSA_WITH_API
  api(this, _app, this),
#endif
  chain(_chain),
  trustedIssuer(""),
  issuerKey("")
{
	configLoad();
}

#ifdef IOTSA_WITH_WEB
void
IotsaCapabilityMod::handler() {
  String _trustedIssuer = server->arg("trustedIssuer");
  String _issuerKey = server->arg("issuerKey");
  if (_trustedIssuer != "" || _issuerKey != "") {
    if (!iotsaConfig.inConfigurationMode()) {
      server->send(401, "text/plain", "401 Unauthorized, not in configuration mode");
      return;
    }
    if (needsAuthentication("capabilities")) return;
    if (_trustedIssuer != "") trustedIssuer = _trustedIssuer;
    if (_issuerKey != "") issuerKey = _issuerKey;
    configSave();
    server->send(200, "text/plain", "ok\r\n");
    return;
  }
  String message = "<title>Capability Authority</title>
Capability Authority
";
  if (!iotsaConfig.inConfigurationMode())
    message += "
Note: You must be in configuration mode to be able to change issuer or key.
";
  message += "<form method='get'>Issuer: <input name='trustedIssuer' value='";
  message += htmlEncode(trustedIssuer);
  message += "'>
Current shared key is secret, but length is ";
  message += String(issuerKey.length());
  message += ".
New key: <input name='issuerKey'>
<input type='Submit'></form>";

  server->send(200, "text/html", message);
}

String IotsaCapabilityMod::info() {
  String message = "
Capabilities enabled.";
  message += " See /capabilities to change settings.";
  message += "
";
  return message;
}
#endif // IOTSA_WITH_WEB

#ifdef IOTSA_WITH_API
bool IotsaCapabilityMod::getHandler(const char *path, JsonObject& reply) {
  if (strcmp(path, "/api/capabilities") != 0) return false;
  reply["trustedIssuer"] = trustedIssuer;
  reply["issuerKeyLength"] = issuerKey.length();
  return true;
}

bool IotsaCapabilityMod::putHandler(const char *path, const JsonVariant& request, JsonObject& reply) {
  if (strcmp(path, "/api/capabilities") != 0) return false;
  if (!iotsaConfig.inConfigurationMode()) return false;
  bool anyChanged = false;
  JsonObject& reqObj = request.as<JsonObject>();
  if (reqObj.containsKey("trustedIssuer")) {
    trustedIssuer = reqObj.get<String>("trustedIssuer");
    anyChanged = true;
  }
  if (reqObj.containsKey("issuerKey")) {
    issuerKey = reqObj.get<String>("issuerKey");
    anyChanged = true;
  }
  if (anyChanged) {
    configSave();
  }
  return anyChanged;
}

bool IotsaCapabilityMod::postHandler(const char *path, const JsonVariant& request, JsonObject& reply) {
  return false;
}
#endif // IOTSA_WITH_API

void IotsaCapabilityMod::setup() {
  configLoad();
}

void IotsaCapabilityMod::serverSetup() {
#ifdef IOTSA_WITH_WEB
  server->on("/capabilities", std::bind(&IotsaCapabilityMod::handler, this));
#endif
#ifdef IOTSA_WITH_API
  api.setup("/api/capabilities", true, true, false);
  name = "capabilities";
#endif
}

void IotsaCapabilityMod::configLoad() {
  IotsaConfigFileLoad cf("/config/capabilities.cfg");
  cf.get("issuer", trustedIssuer, "");
  cf.get("key", issuerKey, "");
}

void IotsaCapabilityMod::configSave() {
  IotsaConfigFileSave cf("/config/capabilities.cfg");
  cf.put("issuer", trustedIssuer);
  cf.put("key", issuerKey);
  IotsaSerial.print("Saved capabilities.cfg, issuer=");
  IotsaSerial.print(trustedIssuer);
  IotsaSerial.print(", key length=");
  IotsaSerial.println(issuerKey.length());
}

void IotsaCapabilityMod::loop() {
}

bool IotsaCapabilityMod::allows(const char *obj, IotsaApiOperation verb) {
#ifdef IOTSA_WITH_HTTP_OR_HTTPS
  loadCapabilitiesFromRequest();
#endif
#ifdef IOTSA_WITH_COAP
  // Need to load capability from coap headers, somehow...
#endif
  if (capabilities) {
    if (capabilities->allows(obj, verb)) {
      IFDEBUGX IotsaSerial.print("Capability allows operation on ");
      IFDEBUGX IotsaSerial.println(obj);
      return true;
    }
    IFDEBUGX IotsaSerial.print("Capability does NOT allow operation on ");
    IFDEBUGX IotsaSerial.println(obj);
  }
  // If no rights fall back to username/password authentication
  return chain.allows(obj, verb);
}

bool IotsaCapabilityMod::allows(const char *right) {
  // If no rights fall back to username/password authentication
  return chain.allows(right);
}
#ifdef IOTSA_WITH_HTTP_OR_HTTPS
void IotsaCapabilityMod::loadCapabilitiesFromRequest() {

  // Free old capabilities
  IotsaCapability **cpp;
  for (cpp=&capabilities; *cpp; cpp=&(*cpp)->next) free(*cpp);
  capabilities = NULL;

  // Check that we can load and verify capabilities
  if (trustedIssuer == "" || issuerKey == "") return;

  // Load the bearer token from the request
  if (!server->hasHeader("Authorization")) {
    IFDEBUGX Serial.println("No authorization header in request");
    return;
  }
  String authHeader = server->header("Authorization");
  if (!authHeader.startsWith("Bearer ")) {
    IFDEBUGX Serial.println("No bearer token in request");
    return;
  }
  String token = authHeader.substring(7);

  // Decode the bearer token
  ArduinoJWT decoder(issuerKey);
  String payload;
  bool ok = decoder.decodeJWT(token, payload);
  // If decode returned false the token wasn't signed with the correct key.
  if (!ok) {
    IFDEBUGX IotsaSerial.println("Did not decode correctly with key");
    return;
  }
  DynamicJsonBuffer jsonBuffer;
  JsonObject& root = jsonBuffer.parseObject(payload);

  // check that issuer matches
  String issuer = root["iss"];
  if (issuer != trustedIssuer) {
    IFDEBUGX IotsaSerial.print("Issuer did not match, wtd=");
    IFDEBUGX IotsaSerial.print(trustedIssuer);
    IFDEBUGX IotsaSerial.print(", got=");
    IFDEBUGX IotsaSerial.println(issuer);
    return;
  }

  // Check that the audience matches
  if (root.containsKey("aud")) {
    JsonVariant audience = root["aud"];
    String myUrl("http://");
    myUrl += iotsaConfig.hostName;
    myUrl += ".local";
    if (audience != "*" && !stringContainedIn(myUrl.c_str(), audience)) {
      IFDEBUGX IotsaSerial.print("Audience did not match, wtd=");
      IFDEBUGX IotsaSerial.print(myUrl);
      IFDEBUGX IotsaSerial.print(", got=");
      IFDEBUGX IotsaSerial.println(audience.as<String>());
      return;
    }
  }
  const char *obj = root.get<char*>("obj");
  IotsaCapabilityObjectScope get = getRightFrom(root["get"]);
  IotsaCapabilityObjectScope put = getRightFrom(root["put"]);
  IotsaCapabilityObjectScope post = getRightFrom(root["post"]);
  IFDEBUGX IotsaSerial.print("capability for ");
  IFDEBUGX IotsaSerial.print(obj);
  IFDEBUGX IotsaSerial.print(", get=");
  IFDEBUGX IotsaSerial.print(int(get));
  IFDEBUGX IotsaSerial.print(", put=");
  IFDEBUGX IotsaSerial.print(int(put));
  IFDEBUGX IotsaSerial.print(", post=");
  IFDEBUGX IotsaSerial.print(int(post));
  IFDEBUGX IotsaSerial.println(" loaded");
  capabilities = new IotsaCapability(obj, get, put, post);
}
#endif // IOTSA_WITH_HTTP_OR_HTTPS<commit_msg>Check for hostname (not url) in bearer token<commit_after>#include "iotsa.h"
#include "iotsaCapabilities.h"
#include "iotsaConfigFile.h"
#include <ArduinoJWT.h>
#include <ArduinoJson.h>

#define IFDEBUGX if(1)

// Static method to check whether a string exactly matches a Json object,
// or is included in the Json object if it is an array.
static bool stringContainedIn(const char *wanted, JsonVariant& got) {
  if (got.is<char*>()) {
    return strcmp(wanted, got.as<const char *>()) == 0;
  }
  if (!got.is<JsonArray>()) {
    return false;
  }
  JsonArray& gotArray = got.as<JsonArray>();
  for(size_t i=0; i<gotArray.size(); i++) {
    const char *gotItem = gotArray[i];
    if (strcmp(gotItem, wanted) == 0) {
      return true;
    }
  }
  return false;
}

// Get a scope indicator from a JSON variant
static IotsaCapabilityObjectScope getRightFrom(const JsonVariant& arg) {
  if (!arg.is<char*>()) return IOTSA_SCOPE_NONE;
  const char *argStr = arg.as<char*>();
  if (strcmp(argStr, "self") == 0) return IOTSA_SCOPE_SELF;
  if (strcmp(argStr, "descendent-or-self") == 0) return IOTSA_SCOPE_FULL;
  if (strcmp(argStr, "descendent") == 0) return IOTSA_SCOPE_CHILD;
  if (strcmp(argStr, "child") == 0) return IOTSA_SCOPE_CHILD;
  return IOTSA_SCOPE_NONE;
}

bool IotsaCapability::allows(const char *_obj, IotsaApiOperation verb) {
  IotsaCapabilityObjectScope scope = scopes[int(verb)];
  int matchLength = obj.length();
  switch(scope) {
    case IOTSA_SCOPE_NONE:
      break;
    case IOTSA_SCOPE_SELF:
      if (strcmp(obj.c_str(), _obj) == 0)
        return true;
      break;
    case IOTSA_SCOPE_FULL:
      if (strncmp(obj.c_str(), _obj, matchLength) == 0) {
        char nextCh = _obj[matchLength];
        if (nextCh == '\0' || nextCh == '/')
          return true;
      }
      break;
    case IOTSA_SCOPE_CHILD:
      if (strncmp(obj.c_str(), _obj, matchLength) == 0) {
        char nextCh = _obj[matchLength];
        if (nextCh == '/')
          return true;
      }
      break;
  }
  // See if there is a next capabiliy we can check, otherwise we don't have permission.
  if (next) return next->allows(_obj, verb);
  return false;
}

IotsaCapabilityMod::IotsaCapabilityMod(IotsaApplication &_app, IotsaAuthenticationProvider& _chain)
:	IotsaAuthMod(_app),
  capabilities(NULL),
#ifdef IOTSA_WITH_API
  api(this, _app, this),
#endif
  chain(_chain),
  trustedIssuer(""),
  issuerKey("")
{
	configLoad();
}

#ifdef IOTSA_WITH_WEB
void
IotsaCapabilityMod::handler() {
  String _trustedIssuer = server->arg("trustedIssuer");
  String _issuerKey = server->arg("issuerKey");
  if (_trustedIssuer != "" || _issuerKey != "") {
    if (!iotsaConfig.inConfigurationMode()) {
      server->send(401, "text/plain", "401 Unauthorized, not in configuration mode");
      return;
    }
    if (needsAuthentication("capabilities")) return;
    if (_trustedIssuer != "") trustedIssuer = _trustedIssuer;
    if (_issuerKey != "") issuerKey = _issuerKey;
    configSave();
    server->send(200, "text/plain", "ok\r\n");
    return;
  }
  String message = "<title>Capability Authority</title>
Capability Authority
";
  if (!iotsaConfig.inConfigurationMode())
    message += "
Note: You must be in configuration mode to be able to change issuer or key.
";
  message += "<form method='get'>Issuer: <input name='trustedIssuer' value='";
  message += htmlEncode(trustedIssuer);
  message += "'>
Current shared key is secret, but length is ";
  message += String(issuerKey.length());
  message += ".
New key: <input name='issuerKey'>
<input type='Submit'></form>";

  server->send(200, "text/html", message);
}

String IotsaCapabilityMod::info() {
  String message = "
Capabilities enabled.";
  message += " See /capabilities to change settings.";
  message += "
";
  return message;
}
#endif // IOTSA_WITH_WEB

#ifdef IOTSA_WITH_API
bool IotsaCapabilityMod::getHandler(const char *path, JsonObject& reply) {
  if (strcmp(path, "/api/capabilities") != 0) return false;
  reply["trustedIssuer"] = trustedIssuer;
  reply["issuerKeyLength"] = issuerKey.length();
  return true;
}

bool IotsaCapabilityMod::putHandler(const char *path, const JsonVariant& request, JsonObject& reply) {
  if (strcmp(path, "/api/capabilities") != 0) return false;
  if (!iotsaConfig.inConfigurationMode()) return false;
  bool anyChanged = false;
  JsonObject& reqObj = request.as<JsonObject>();
  if (reqObj.containsKey("trustedIssuer")) {
    trustedIssuer = reqObj.get<String>("trustedIssuer");
    anyChanged = true;
  }
  if (reqObj.containsKey("issuerKey")) {
    issuerKey = reqObj.get<String>("issuerKey");
    anyChanged = true;
  }
  if (anyChanged) {
    configSave();
  }
  return anyChanged;
}

bool IotsaCapabilityMod::postHandler(const char *path, const JsonVariant& request, JsonObject& reply) {
  return false;
}
#endif // IOTSA_WITH_API

void IotsaCapabilityMod::setup() {
  configLoad();
}

void IotsaCapabilityMod::serverSetup() {
#ifdef IOTSA_WITH_WEB
  server->on("/capabilities", std::bind(&IotsaCapabilityMod::handler, this));
#endif
#ifdef IOTSA_WITH_API
  api.setup("/api/capabilities", true, true, false);
  name = "capabilities";
#endif
}

void IotsaCapabilityMod::configLoad() {
  IotsaConfigFileLoad cf("/config/capabilities.cfg");
  cf.get("issuer", trustedIssuer, "");
  cf.get("key", issuerKey, "");
}

void IotsaCapabilityMod::configSave() {
  IotsaConfigFileSave cf("/config/capabilities.cfg");
  cf.put("issuer", trustedIssuer);
  cf.put("key", issuerKey);
  IotsaSerial.print("Saved capabilities.cfg, issuer=");
  IotsaSerial.print(trustedIssuer);
  IotsaSerial.print(", key length=");
  IotsaSerial.println(issuerKey.length());
}

void IotsaCapabilityMod::loop() {
}

bool IotsaCapabilityMod::allows(const char *obj, IotsaApiOperation verb) {
#ifdef IOTSA_WITH_HTTP_OR_HTTPS
  loadCapabilitiesFromRequest();
#endif
#ifdef IOTSA_WITH_COAP
  // Need to load capability from coap headers, somehow...
#endif
  if (capabilities) {
    if (capabilities->allows(obj, verb)) {
      IFDEBUGX IotsaSerial.print("Capability allows operation on ");
      IFDEBUGX IotsaSerial.println(obj);
      return true;
    }
    IFDEBUGX IotsaSerial.print("Capability does NOT allow operation on ");
    IFDEBUGX IotsaSerial.println(obj);
  }
  // If no rights fall back to username/password authentication
  return chain.allows(obj, verb);
}

bool IotsaCapabilityMod::allows(const char *right) {
  // If no rights fall back to username/password authentication
  return chain.allows(right);
}
#ifdef IOTSA_WITH_HTTP_OR_HTTPS
void IotsaCapabilityMod::loadCapabilitiesFromRequest() {

  // Free old capabilities
  IotsaCapability **cpp;
  for (cpp=&capabilities; *cpp; cpp=&(*cpp)->next) free(*cpp);
  capabilities = NULL;

  // Check that we can load and verify capabilities
  if (trustedIssuer == "" || issuerKey == "") return;

  // Load the bearer token from the request
  if (!server->hasHeader("Authorization")) {
    IFDEBUGX Serial.println("No authorization header in request");
    return;
  }
  String authHeader = server->header("Authorization");
  if (!authHeader.startsWith("Bearer ")) {
    IFDEBUGX Serial.println("No bearer token in request");
    return;
  }
  String token = authHeader.substring(7);

  // Decode the bearer token
  ArduinoJWT decoder(issuerKey);
  String payload;
  bool ok = decoder.decodeJWT(token, payload);
  // If decode returned false the token wasn't signed with the correct key.
  if (!ok) {
    IFDEBUGX IotsaSerial.println("Did not decode correctly with key");
    return;
  }
  DynamicJsonBuffer jsonBuffer;
  JsonObject& root = jsonBuffer.parseObject(payload);

  // check that issuer matches
  String issuer = root["iss"];
  if (issuer != trustedIssuer) {
    IFDEBUGX IotsaSerial.print("Issuer did not match, wtd=");
    IFDEBUGX IotsaSerial.print(trustedIssuer);
    IFDEBUGX IotsaSerial.print(", got=");
    IFDEBUGX IotsaSerial.println(issuer);
    return;
  }

  if (root.containsKey("aud")) {
    JsonVariant audience = root["aud"];
    String myFullName = iotsaConfig.hostName + ".local";
    if (audience != "*" && audience != myFullName) {
      IFDEBUGX IotsaSerial.print("Audience did not match, wtd=");
      IFDEBUGX IotsaSerial.print(myFullName);
      IFDEBUGX IotsaSerial.print(", got=");
      IFDEBUGX IotsaSerial.println(audience.as<String>());
      return;
    }
  }
  const char *obj = root.get<char*>("obj");
  IotsaCapabilityObjectScope get = getRightFrom(root["get"]);
  IotsaCapabilityObjectScope put = getRightFrom(root["put"]);
  IotsaCapabilityObjectScope post = getRightFrom(root["post"]);
  IFDEBUGX IotsaSerial.print("capability for ");
  IFDEBUGX IotsaSerial.print(obj);
  IFDEBUGX IotsaSerial.print(", get=");
  IFDEBUGX IotsaSerial.print(int(get));
  IFDEBUGX IotsaSerial.print(", put=");
  IFDEBUGX IotsaSerial.print(int(put));
  IFDEBUGX IotsaSerial.print(", post=");
  IFDEBUGX IotsaSerial.print(int(post));
  IFDEBUGX IotsaSerial.println(" loaded");
  capabilities = new IotsaCapability(obj, get, put, post);
}
#endif // IOTSA_WITH_HTTP_OR_HTTPS<|endoftext|>


<commit_before>/*
 * author: Max Kellermann <mk@cm4all.com>
 */

#include "istream_stopwatch.hxx"
#include "istream_internal.hxx"
#include "istream_forward.hxx"
#include "stopwatch.h"
#include "util/Cast.hxx"

#include <assert.h>

struct istream_stopwatch {
    struct istream output;

    struct istream *input;

    struct stopwatch *stopwatch;
};

/*
 * istream handler
 *
 */

static void
stopwatch_input_eof(void *ctx)
{
    auto *stopwatch = (struct istream_stopwatch *)ctx;

    stopwatch_event(stopwatch->stopwatch, "end");
    stopwatch_dump(stopwatch->stopwatch);

    istream_deinit_eof(&stopwatch->output);
}

static void
stopwatch_input_abort(GError *error, void *ctx)
{
    auto *stopwatch = (struct istream_stopwatch *)ctx;

    stopwatch_event(stopwatch->stopwatch, "abort");
    stopwatch_dump(stopwatch->stopwatch);

    istream_deinit_abort(&stopwatch->output, error);
}

static constexpr struct istream_handler stopwatch_input_handler = {
    .data = istream_forward_data,
    .direct = istream_forward_direct,
    .eof = stopwatch_input_eof,
    .abort = stopwatch_input_abort,
};

/*
 * istream implementation
 *
 */

static inline struct istream_stopwatch *
istream_to_stopwatch(struct istream *istream)
{
    return &ContainerCast2(*istream, &istream_stopwatch::output);
}

static void
istream_stopwatch_read(struct istream *istream)
{
    struct istream_stopwatch *stopwatch = istream_to_stopwatch(istream);

    istream_handler_set_direct(stopwatch->input,
                               stopwatch->output.handler_direct);

    istream_read(stopwatch->input);
}

static int
istream_stopwatch_as_fd(struct istream *istream)
{
    struct istream_stopwatch *stopwatch = istream_to_stopwatch(istream);

    int fd = istream_as_fd(stopwatch->input);
    if (fd >= 0) {
        stopwatch_event(stopwatch->stopwatch, "as_fd");
        stopwatch_dump(stopwatch->stopwatch);
        istream_deinit(&stopwatch->output);
    }

    return fd;
}

static void
istream_stopwatch_close(struct istream *istream)
{
    struct istream_stopwatch *stopwatch = istream_to_stopwatch(istream);

    assert(stopwatch->input != nullptr);

    istream_close_handler(stopwatch->input);
    istream_deinit(&stopwatch->output);
}

static constexpr struct istream_class istream_stopwatch = {
    .read = istream_stopwatch_read,
    .as_fd = istream_stopwatch_as_fd,
    .close = istream_stopwatch_close,
};

/*
 * constructor
 *
 */

struct istream *
istream_stopwatch_new(struct pool *pool, struct istream *input,
                      struct stopwatch *_stopwatch)
{
    assert(input != nullptr);
    assert(!istream_has_handler(input));

    if (_stopwatch == nullptr)
        return input;

    auto stopwatch = NewFromPool<struct istream_stopwatch>(*pool);
    istream_init(&stopwatch->output, &istream_stopwatch, pool);

    istream_assign_handler(&stopwatch->input, input,
                           &stopwatch_input_handler, stopwatch,
                           0);

    stopwatch->stopwatch = _stopwatch;

    return &stopwatch->output;
}
<commit_msg>istream_stopwatch: rename the struct with CamelCase<commit_after>/*
 * author: Max Kellermann <mk@cm4all.com>
 */

#include "istream_stopwatch.hxx"
#include "istream_internal.hxx"
#include "istream_forward.hxx"
#include "stopwatch.h"
#include "util/Cast.hxx"

#include <assert.h>

struct StopwatchIstream {
    struct istream output;

    struct istream *input;

    struct stopwatch *stopwatch;
};

/*
 * istream handler
 *
 */

static void
stopwatch_input_eof(void *ctx)
{
    auto *stopwatch = (StopwatchIstream *)ctx;

    stopwatch_event(stopwatch->stopwatch, "end");
    stopwatch_dump(stopwatch->stopwatch);

    istream_deinit_eof(&stopwatch->output);
}

static void
stopwatch_input_abort(GError *error, void *ctx)
{
    auto *stopwatch = (StopwatchIstream *)ctx;

    stopwatch_event(stopwatch->stopwatch, "abort");
    stopwatch_dump(stopwatch->stopwatch);

    istream_deinit_abort(&stopwatch->output, error);
}

static constexpr struct istream_handler stopwatch_input_handler = {
    .data = istream_forward_data,
    .direct = istream_forward_direct,
    .eof = stopwatch_input_eof,
    .abort = stopwatch_input_abort,
};

/*
 * istream implementation
 *
 */

static inline StopwatchIstream *
istream_to_stopwatch(struct istream *istream)
{
    return &ContainerCast2(*istream, &StopwatchIstream::output);
}

static void
istream_stopwatch_read(struct istream *istream)
{
    StopwatchIstream *stopwatch = istream_to_stopwatch(istream);

    istream_handler_set_direct(stopwatch->input,
                               stopwatch->output.handler_direct);

    istream_read(stopwatch->input);
}

static int
istream_stopwatch_as_fd(struct istream *istream)
{
    StopwatchIstream *stopwatch = istream_to_stopwatch(istream);

    int fd = istream_as_fd(stopwatch->input);
    if (fd >= 0) {
        stopwatch_event(stopwatch->stopwatch, "as_fd");
        stopwatch_dump(stopwatch->stopwatch);
        istream_deinit(&stopwatch->output);
    }

    return fd;
}

static void
istream_stopwatch_close(struct istream *istream)
{
    StopwatchIstream *stopwatch = istream_to_stopwatch(istream);

    assert(stopwatch->input != nullptr);

    istream_close_handler(stopwatch->input);
    istream_deinit(&stopwatch->output);
}

static constexpr struct istream_class istream_stopwatch = {
    .read = istream_stopwatch_read,
    .as_fd = istream_stopwatch_as_fd,
    .close = istream_stopwatch_close,
};

/*
 * constructor
 *
 */

struct istream *
istream_stopwatch_new(struct pool *pool, struct istream *input,
                      struct stopwatch *_stopwatch)
{
    assert(input != nullptr);
    assert(!istream_has_handler(input));

    if (_stopwatch == nullptr)
        return input;

    auto stopwatch = NewFromPool<StopwatchIstream>(*pool);
    istream_init(&stopwatch->output, &istream_stopwatch, pool);

    istream_assign_handler(&stopwatch->input, input,
                           &stopwatch_input_handler, stopwatch,
                           0);

    stopwatch->stopwatch = _stopwatch;

    return &stopwatch->output;
}
<|endoftext|>