<commit_before>package main

import (
  "database/sql"
  "encoding/json"
  "errors"
  "fmt"
  "net/http"
  "net/url"
  "os"
  "strconv"
  _ "github.com/lib/pq"
  "github.com/rcrowley/go-tigertonic"
  "github.com/rkbodenner/meeple_mover/record"
// Fixture data  "github.com/rkbodenner/parallel_universe/collection"
  "github.com/rkbodenner/parallel_universe/game"
  "github.com/rkbodenner/parallel_universe/session"
)

var players = make([]*game.Player, 0)
var playerIndex = make(map[uint64]*game.Player)

func initPlayerData(db *sql.DB) error {
  rows, err := db.Query("SELECT * FROM players")
  if nil != err {
    return err
  }
  defer rows.Close()
  for rows.Next() {
    var name string
    var id int
    if err := rows.Scan(&id, &name); err != nil {
      return err
    }
    players = append(players, &game.Player{id, name})
  }

  for _,player := range players {
    playerIndex[(uint64)(player.Id)] = player
  }

  fmt.Printf("Loaded %d players from DB\n", len(players))
  return nil
}

var games []*game.Game
var gameIndex = make(map[uint64]*game.Game)

// Add IDs to setup rules for a game, if they exist in the DB
func initSetupRuleIds(db *sql.DB, g *game.Game) error {
  rows, err := db.Query("SELECT id, description FROM setup_rules WHERE game_id = $1", g.Id)
  if nil != err {
     return err
  }
  defer rows.Close()
  for rows.Next() {
    var id int
    var description string
    if err := rows.Scan(&id, &description); nil != err {
      return err
    }
    for _, rule := range g.SetupRules {
      if rule.Description == description {
        rule.Id = id
        break
      }
    }
  }
  return nil
}

func initGameData(db *sql.DB) error {
  /*
  // Fixture data
  games = collection.NewCollection().Games
  for i, game := range games {
    game.Id = (uint)(i+1)
    gameIndex[(uint64)(i+1)] = game

    if err := initSetupRuleIds(db, game); err != nil {
      return err
    }
  }
  */

  gameRecords := &record.GameRecordList{}
  err := gameRecords.FindAll(db)
  if nil != err {
    return err
  }
  games = gameRecords.List()

  for _, game := range games {
    gameIndex[(uint64)(game.Id)] = game
  }

  fmt.Printf("Loaded %d games from DB\n", len(games))
  return nil
}

var sessions []*session.Session
var sessionIndex = make(map[uint64]*session.Session)

func initSessionData(db *sql.DB) error {
  // Fixture data
  /*
  sessions = make([]*session.Session, 2)
  sessions[0] = session.NewSession(games[0], players)
  sessions[0].Step(players[0])
  sessions[0].Step(players[1])

  sessions[1] = session.NewSession(games[1], players)
  sessions[1].Step(players[0])
  sessions[1].Step(players[1])

  for i,session := range sessions[:1] {
    session.Id = (uint)(i+1)
    sessionIndex[(uint64)(i+1)] = session
  }
  */

  // All records from DB
  records := &record.SessionRecordList{}
  err := records.FindAll(db)
  if nil != err {
    return err
  }
  sessions = records.List()
  //*/

  // Update global cache of sessions
  for _, s := range sessions {
    sessionIndex[(uint64)(s.Id)] = s
  }

  fmt.Printf("Loaded %d sessions from DB\n", len(sessions))
  return nil
}

type CollectionHandler struct{}
func (h CollectionHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
  err := json.NewEncoder(w).Encode(games)
  if ( nil != err ) {
    fmt.Fprintln(w, err)
  }
}

type GameHandler struct{}
func (h GameHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
  id_str := r.URL.Query().Get("id")
  id, err := strconv.ParseUint(id_str, 10, 64)
  if nil != err {
    http.Error(w, "Not found", http.StatusNotFound)
    return
  }

  game, ok := gameIndex[id]
  if ok {
    err := json.NewEncoder(w).Encode(game)
    if ( nil != err ) {
      http.Error(w, "Error", http.StatusInternalServerError)
    }
  } else {
    http.Error(w, "Not found", http.StatusNotFound)
  }
}

type PlayersHandler struct{}
func (h PlayersHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
  err := json.NewEncoder(w).Encode(players)
  if ( nil != err ) {
    fmt.Fprintln(w, err)
  }
}

type PlayerHandler struct{}
func (h PlayerHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
  player_id_str := r.URL.Query().Get("player_id")
  player_id, err := strconv.ParseUint(player_id_str, 10, 64)
  if nil != err {
    http.Error(w, "Not found", http.StatusNotFound)
    return
  }

  player, ok := playerIndex[player_id]
  if ok {
    err = json.NewEncoder(w).Encode(player)
    if ( nil != err ) {
      http.Error(w, "Error", http.StatusInternalServerError)
    }
  } else {
    http.Error(w, "Not found", http.StatusNotFound)
  }
}

type SessionsHandler struct{}
func (h SessionsHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
  err := json.NewEncoder(w).Encode(sessions)
  if ( nil != err ) {
    http.Error(w, "Error", http.StatusInternalServerError)
  }
}

type SessionCreateHandler struct {
  db *sql.DB
}
type SessionCreateHash struct {
  StartedDate string `json:"started_date"`
  Game string `json:"game"`
  Players []string `json:"players"`
}
type SessionCreateRequest struct {
  Session SessionCreateHash `json:"session"`
}

func fetchPlayersById(db *sql.DB, playerIds []int) ([]*game.Player, error) {
  players := make([]*game.Player, len(playerIds))

  for i, playerId := range playerIds {
    var name string
    err := db.QueryRow("SELECT name FROM players WHERE id = $1", playerId).Scan(&name)
    if err != nil {
       return players, err
    }
    players[i] = &game.Player{playerId, name}
  }

  return players, nil
}

// Persist a new session
func (handler SessionCreateHandler) marshalFunc() (func(*url.URL, http.Header, *SessionCreateRequest) (int, http.Header, *session.Session, error)) {
  return func(u *url.URL, h http.Header, rq *SessionCreateRequest) (int, http.Header, *session.Session, error) {
    var err error

    var game_id uint64
    game_id, err = strconv.ParseUint(rq.Session.Game, 10, 64)
    if nil != err {
      return http.StatusBadRequest, nil, nil, errors.New("Expected integer game ID")
    }

    player_ids := make([]int, 0)
    for _, player_id_str := range rq.Session.Players {
      player_id, err := strconv.ParseInt(player_id_str, 10, 32)
      if nil != err {
        return http.StatusBadRequest, nil, nil, errors.New("Expected integer player ID")
      }
      player_ids = append(player_ids, (int)(player_id))
    }

    var players []*game.Player
    players, err = fetchPlayersById(handler.db, player_ids)
    if nil != err {
      return http.StatusInternalServerError, nil, nil, err
    }
    fmt.Printf("Found %d matching players\n", len(players))

    session := session.NewSession(gameIndex[game_id], players)
    session.StepAllPlayers()

    err = record.NewSessionRecord(session).Create(handler.db)
    if nil != err {
      return http.StatusInternalServerError, nil, nil, err
    }

    sessionIndex[(uint64)(session.Id)] = session

    session.Print()

    return http.StatusCreated, nil, session, nil
  }
}

type SessionHandler struct{}
func (h SessionHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
  id_str := r.URL.Query().Get("session_id")
  id, err := strconv.ParseUint(id_str, 10, 64)
  if nil != err {
    http.Error(w, "Not found", http.StatusNotFound)
    return
  }

  session, ok := sessionIndex[id]
  if ok {
    err := json.NewEncoder(w).Encode(session)
    if ( nil != err ) {
      http.Error(w, "Error", http.StatusInternalServerError)
    }
  } else {
    http.Error(w, "Not found", http.StatusNotFound)
  }
}

type StepHandler struct{
  db *sql.DB
}
func (h StepHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
  session_id_str := r.URL.Query().Get("session_id")
  session_id, err := strconv.ParseUint(session_id_str, 10, 64)
  if nil != err {
    http.Error(w, "Session not found", http.StatusNotFound)
    return
  }
  session,ok := sessionIndex[session_id]
  if !ok {
    http.Error(w, "Session not found", http.StatusNotFound)
    return
  }

  player_id_str := r.URL.Query().Get("player_id")
  player_id, err := strconv.ParseUint(player_id_str, 10, 64)
  if nil != err {
    http.Error(w, "Player not found", http.StatusNotFound)
    return
  }
  player, ok := playerIndex[player_id]
  if !ok {
    http.Error(w, "Player not found", http.StatusNotFound)
    return
  }

  step_desc,err := url.QueryUnescape(r.URL.Query().Get("step_desc"))
  for _,step := range session.SetupSteps {
    if ( step.Rule.Description == step_desc && step.CanBeOwnedBy(player) ) {
      step.Finish()  // FIXME. Should look in request data to see what to change.

      rec := &record.SetupStepRecord{Step: step, SessionId: (int)(session.Id)}
      err := rec.Update(h.db)
      if nil != err {
        // FIXME: Revert to the previous state if we can't save.
        http.Error(w, fmt.Sprintf("Error saving update to step: %s", err), http.StatusInternalServerError)
        return
      }

      nextStep := session.Step(player)

      if nextStep != step && nil != nextStep {
        lastAssignmentRec := &record.SetupStepAssignmentRecord{session, player, step.Rule}
        err = lastAssignmentRec.Delete(h.db)
        if nil != err {
          http.Error(w, fmt.Sprintf("Error removing assignment of last step: %s", err), http.StatusInternalServerError)
          return
        }
        nextAssignmentRec := &record.SetupStepAssignmentRecord{session, player, nextStep.Rule}
        err = nextAssignmentRec.Create(h.db)
        if nil != err {
          http.Error(w, fmt.Sprintf("Error creating assignment of next step: %s", err), http.StatusInternalServerError)
          return
        }
      }

      session.Print()
      return
    }
  }
  http.Error(w, "Step not found", http.StatusNotFound)
}

func main() {
  connectString := "user=ralph dbname=meeple_mover sslmode=disable"
  herokuConnectString := os.Getenv("HEROKU_POSTGRESQL_SILVER_URL")
  if herokuConnectString != "" {
    connectString = herokuConnectString
  }

  db, err := sql.Open("postgres", connectString)
  if err != nil {
    fmt.Print(err)
  } else {
    fmt.Println("Connected to database")
  }
  defer db.Close()

  err = initPlayerData(db)
  if err != nil {
    fmt.Printf("Error initializing players: %s\n", err)
  }
  err = initGameData(db)
  if err != nil {
    fmt.Printf("Error initializing games: %s\n", err)
  }
  err = initSessionData(db)
  if err != nil {
    fmt.Printf("Error initializing sessions: %s\n", err)
  }

  var origin string
  origin = os.Getenv("MEEPLE_MOVER_ORIGIN_URL")
  if "" == origin {
    origin = "http://localhost:8000"
  }
  cors := tigertonic.NewCORSBuilder().AddAllowedOrigins(origin).AddAllowedHeaders("Content-Type")
  fmt.Printf("Allowed CORS origin %s\n", origin)

  mux := tigertonic.NewTrieServeMux()
  mux.Handle("GET", "/games", cors.Build(CollectionHandler{}))
  mux.Handle("GET", "/games/{id}", cors.Build(GameHandler{}))
  mux.Handle("GET", "/players", cors.Build(PlayersHandler{}))
  mux.Handle("GET", "/players/{player_id}", cors.Build(PlayerHandler{}))
  mux.Handle("GET", "/sessions", cors.Build(SessionsHandler{}))
  mux.Handle("POST", "/sessions", cors.Build(tigertonic.Marshaled(SessionCreateHandler{db}.marshalFunc())))
  mux.Handle("GET", "/sessions/{session_id}", cors.Build(SessionHandler{}))
  mux.Handle("PUT", "/sessions/{session_id}/players/{player_id}/steps/{step_desc}", cors.Build(StepHandler{db}))

  var port string
  port = os.Getenv("PORT")
  if "" == port {
    port = "8080"
  }

  http.ListenAndServe(fmt.Sprintf(":%s", port), mux)
}
<commit_msg>Update session cache after creating one<commit_after>package main

import (
  "database/sql"
  "encoding/json"
  "errors"
  "fmt"
  "net/http"
  "net/url"
  "os"
  "strconv"
  _ "github.com/lib/pq"
  "github.com/rcrowley/go-tigertonic"
  "github.com/rkbodenner/meeple_mover/record"
// Fixture data  "github.com/rkbodenner/parallel_universe/collection"
  "github.com/rkbodenner/parallel_universe/game"
  "github.com/rkbodenner/parallel_universe/session"
)

var players = make([]*game.Player, 0)
var playerIndex = make(map[uint64]*game.Player)

func initPlayerData(db *sql.DB) error {
  rows, err := db.Query("SELECT * FROM players")
  if nil != err {
    return err
  }
  defer rows.Close()
  for rows.Next() {
    var name string
    var id int
    if err := rows.Scan(&id, &name); err != nil {
      return err
    }
    players = append(players, &game.Player{id, name})
  }

  for _,player := range players {
    playerIndex[(uint64)(player.Id)] = player
  }

  fmt.Printf("Loaded %d players from DB\n", len(players))
  return nil
}

var games []*game.Game
var gameIndex = make(map[uint64]*game.Game)

// Add IDs to setup rules for a game, if they exist in the DB
func initSetupRuleIds(db *sql.DB, g *game.Game) error {
  rows, err := db.Query("SELECT id, description FROM setup_rules WHERE game_id = $1", g.Id)
  if nil != err {
     return err
  }
  defer rows.Close()
  for rows.Next() {
    var id int
    var description string
    if err := rows.Scan(&id, &description); nil != err {
      return err
    }
    for _, rule := range g.SetupRules {
      if rule.Description == description {
        rule.Id = id
        break
      }
    }
  }
  return nil
}

func initGameData(db *sql.DB) error {
  /*
  // Fixture data
  games = collection.NewCollection().Games
  for i, game := range games {
    game.Id = (uint)(i+1)
    gameIndex[(uint64)(i+1)] = game

    if err := initSetupRuleIds(db, game); err != nil {
      return err
    }
  }
  */

  gameRecords := &record.GameRecordList{}
  err := gameRecords.FindAll(db)
  if nil != err {
    return err
  }
  games = gameRecords.List()

  for _, game := range games {
    gameIndex[(uint64)(game.Id)] = game
  }

  fmt.Printf("Loaded %d games from DB\n", len(games))
  return nil
}

var sessions []*session.Session
var sessionIndex = make(map[uint64]*session.Session)

func initSessionData(db *sql.DB) error {
  // Fixture data
  /*
  sessions = make([]*session.Session, 2)
  sessions[0] = session.NewSession(games[0], players)
  sessions[0].Step(players[0])
  sessions[0].Step(players[1])

  sessions[1] = session.NewSession(games[1], players)
  sessions[1].Step(players[0])
  sessions[1].Step(players[1])

  for i,session := range sessions[:1] {
    session.Id = (uint)(i+1)
    sessionIndex[(uint64)(i+1)] = session
  }
  */

  // All records from DB
  records := &record.SessionRecordList{}
  err := records.FindAll(db)
  if nil != err {
    return err
  }
  sessions = records.List()
  //*/

  // Update global cache of sessions
  for _, s := range sessions {
    sessionIndex[(uint64)(s.Id)] = s
  }

  fmt.Printf("Loaded %d sessions from DB\n", len(sessions))
  return nil
}

type CollectionHandler struct{}
func (h CollectionHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
  err := json.NewEncoder(w).Encode(games)
  if ( nil != err ) {
    fmt.Fprintln(w, err)
  }
}

type GameHandler struct{}
func (h GameHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
  id_str := r.URL.Query().Get("id")
  id, err := strconv.ParseUint(id_str, 10, 64)
  if nil != err {
    http.Error(w, "Not found", http.StatusNotFound)
    return
  }

  game, ok := gameIndex[id]
  if ok {
    err := json.NewEncoder(w).Encode(game)
    if ( nil != err ) {
      http.Error(w, "Error", http.StatusInternalServerError)
    }
  } else {
    http.Error(w, "Not found", http.StatusNotFound)
  }
}

type PlayersHandler struct{}
func (h PlayersHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
  err := json.NewEncoder(w).Encode(players)
  if ( nil != err ) {
    fmt.Fprintln(w, err)
  }
}

type PlayerHandler struct{}
func (h PlayerHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
  player_id_str := r.URL.Query().Get("player_id")
  player_id, err := strconv.ParseUint(player_id_str, 10, 64)
  if nil != err {
    http.Error(w, "Not found", http.StatusNotFound)
    return
  }

  player, ok := playerIndex[player_id]
  if ok {
    err = json.NewEncoder(w).Encode(player)
    if ( nil != err ) {
      http.Error(w, "Error", http.StatusInternalServerError)
    }
  } else {
    http.Error(w, "Not found", http.StatusNotFound)
  }
}

type SessionsHandler struct{}
func (h SessionsHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
  err := json.NewEncoder(w).Encode(sessions)
  if ( nil != err ) {
    http.Error(w, "Error", http.StatusInternalServerError)
  }
}

type SessionCreateHandler struct {
  db *sql.DB
}
type SessionCreateHash struct {
  StartedDate string `json:"started_date"`
  Game string `json:"game"`
  Players []string `json:"players"`
}
type SessionCreateRequest struct {
  Session SessionCreateHash `json:"session"`
}

func fetchPlayersById(db *sql.DB, playerIds []int) ([]*game.Player, error) {
  players := make([]*game.Player, len(playerIds))

  for i, playerId := range playerIds {
    var name string
    err := db.QueryRow("SELECT name FROM players WHERE id = $1", playerId).Scan(&name)
    if err != nil {
       return players, err
    }
    players[i] = &game.Player{playerId, name}
  }

  return players, nil
}

// Persist a new session
func (handler SessionCreateHandler) marshalFunc() (func(*url.URL, http.Header, *SessionCreateRequest) (int, http.Header, *session.Session, error)) {
  return func(u *url.URL, h http.Header, rq *SessionCreateRequest) (int, http.Header, *session.Session, error) {
    var err error

    var game_id uint64
    game_id, err = strconv.ParseUint(rq.Session.Game, 10, 64)
    if nil != err {
      return http.StatusBadRequest, nil, nil, errors.New("Expected integer game ID")
    }

    player_ids := make([]int, 0)
    for _, player_id_str := range rq.Session.Players {
      player_id, err := strconv.ParseInt(player_id_str, 10, 32)
      if nil != err {
        return http.StatusBadRequest, nil, nil, errors.New("Expected integer player ID")
      }
      player_ids = append(player_ids, (int)(player_id))
    }

    var players []*game.Player
    players, err = fetchPlayersById(handler.db, player_ids)
    if nil != err {
      return http.StatusInternalServerError, nil, nil, err
    }
    fmt.Printf("Found %d matching players\n", len(players))

    session := session.NewSession(gameIndex[game_id], players)
    session.StepAllPlayers()

    err = record.NewSessionRecord(session).Create(handler.db)
    if nil != err {
      return http.StatusInternalServerError, nil, nil, err
    }

    sessions = append(sessions, session)
    sessionIndex[(uint64)(session.Id)] = session

    session.Print()

    return http.StatusCreated, nil, session, nil
  }
}

type SessionHandler struct{}
func (h SessionHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
  id_str := r.URL.Query().Get("session_id")
  id, err := strconv.ParseUint(id_str, 10, 64)
  if nil != err {
    http.Error(w, "Not found", http.StatusNotFound)
    return
  }

  session, ok := sessionIndex[id]
  if ok {
    err := json.NewEncoder(w).Encode(session)
    if ( nil != err ) {
      http.Error(w, "Error", http.StatusInternalServerError)
    }
  } else {
    http.Error(w, "Not found", http.StatusNotFound)
  }
}

type StepHandler struct{
  db *sql.DB
}
func (h StepHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
  session_id_str := r.URL.Query().Get("session_id")
  session_id, err := strconv.ParseUint(session_id_str, 10, 64)
  if nil != err {
    http.Error(w, "Session not found", http.StatusNotFound)
    return
  }
  session,ok := sessionIndex[session_id]
  if !ok {
    http.Error(w, "Session not found", http.StatusNotFound)
    return
  }

  player_id_str := r.URL.Query().Get("player_id")
  player_id, err := strconv.ParseUint(player_id_str, 10, 64)
  if nil != err {
    http.Error(w, "Player not found", http.StatusNotFound)
    return
  }
  player, ok := playerIndex[player_id]
  if !ok {
    http.Error(w, "Player not found", http.StatusNotFound)
    return
  }

  step_desc,err := url.QueryUnescape(r.URL.Query().Get("step_desc"))
  for _,step := range session.SetupSteps {
    if ( step.Rule.Description == step_desc && step.CanBeOwnedBy(player) ) {
      step.Finish()  // FIXME. Should look in request data to see what to change.

      rec := &record.SetupStepRecord{Step: step, SessionId: (int)(session.Id)}
      err := rec.Update(h.db)
      if nil != err {
        // FIXME: Revert to the previous state if we can't save.
        http.Error(w, fmt.Sprintf("Error saving update to step: %s", err), http.StatusInternalServerError)
        return
      }

      nextStep := session.Step(player)

      if nextStep != step && nil != nextStep {
        lastAssignmentRec := &record.SetupStepAssignmentRecord{session, player, step.Rule}
        err = lastAssignmentRec.Delete(h.db)
        if nil != err {
          http.Error(w, fmt.Sprintf("Error removing assignment of last step: %s", err), http.StatusInternalServerError)
          return
        }
        nextAssignmentRec := &record.SetupStepAssignmentRecord{session, player, nextStep.Rule}
        err = nextAssignmentRec.Create(h.db)
        if nil != err {
          http.Error(w, fmt.Sprintf("Error creating assignment of next step: %s", err), http.StatusInternalServerError)
          return
        }
      }

      session.Print()
      return
    }
  }
  http.Error(w, "Step not found", http.StatusNotFound)
}

func main() {
  connectString := "user=ralph dbname=meeple_mover sslmode=disable"
  herokuConnectString := os.Getenv("HEROKU_POSTGRESQL_SILVER_URL")
  if herokuConnectString != "" {
    connectString = herokuConnectString
  }

  db, err := sql.Open("postgres", connectString)
  if err != nil {
    fmt.Print(err)
  } else {
    fmt.Println("Connected to database")
  }
  defer db.Close()

  err = initPlayerData(db)
  if err != nil {
    fmt.Printf("Error initializing players: %s\n", err)
  }
  err = initGameData(db)
  if err != nil {
    fmt.Printf("Error initializing games: %s\n", err)
  }
  err = initSessionData(db)
  if err != nil {
    fmt.Printf("Error initializing sessions: %s\n", err)
  }

  var origin string
  origin = os.Getenv("MEEPLE_MOVER_ORIGIN_URL")
  if "" == origin {
    origin = "http://localhost:8000"
  }
  cors := tigertonic.NewCORSBuilder().AddAllowedOrigins(origin).AddAllowedHeaders("Content-Type")
  fmt.Printf("Allowed CORS origin %s\n", origin)

  mux := tigertonic.NewTrieServeMux()
  mux.Handle("GET", "/games", cors.Build(CollectionHandler{}))
  mux.Handle("GET", "/games/{id}", cors.Build(GameHandler{}))
  mux.Handle("GET", "/players", cors.Build(PlayersHandler{}))
  mux.Handle("GET", "/players/{player_id}", cors.Build(PlayerHandler{}))
  mux.Handle("GET", "/sessions", cors.Build(SessionsHandler{}))
  mux.Handle("POST", "/sessions", cors.Build(tigertonic.Marshaled(SessionCreateHandler{db}.marshalFunc())))
  mux.Handle("GET", "/sessions/{session_id}", cors.Build(SessionHandler{}))
  mux.Handle("PUT", "/sessions/{session_id}/players/{player_id}/steps/{step_desc}", cors.Build(StepHandler{db}))

  var port string
  port = os.Getenv("PORT")
  if "" == port {
    port = "8080"
  }

  http.ListenAndServe(fmt.Sprintf(":%s", port), mux)
}
<|endoftext|>


<commit_before>package function

import (
	"fmt"

	enry "gopkg.in/src-d/enry.v1"
	"gopkg.in/src-d/go-mysql-server.v0/sql"
)

// Language gets the language of a file given its path and
// the optional content of the file.
type Language struct {
	Left  sql.Expression
	Right sql.Expression
}

// NewLanguage creates a new Language UDF.
func NewLanguage(args ...sql.Expression) (sql.Expression, error) {
	var left, right sql.Expression
	switch len(args) {
	case 1:
		left = args[0]
	case 2:
		left = args[0]
		right = args[1]
	default:
		return nil, sql.ErrInvalidArgumentNumber.New("1 or 2", len(args))
	}

	return &Language{left, right}, nil
}

// Resolved implements the Expression interface.
func (f *Language) Resolved() bool {
	return f.Left.Resolved() && (f.Right == nil || f.Right.Resolved())
}

func (f *Language) String() string {
	if f.Right == nil {
		return fmt.Sprintf("language(%s)", f.Left)
	}
	return fmt.Sprintf("language(%s, %s)", f.Left, f.Right)
}

// IsNullable implements the Expression interface.
func (f *Language) IsNullable() bool {
	return f.Left.IsNullable() || (f.Right != nil && f.Right.IsNullable())
}

// Type implements the Expression interface.
func (Language) Type() sql.Type {
	return sql.Text
}

// TransformUp implements the Expression interface.
func (f *Language) TransformUp(fn sql.TransformExprFunc) (sql.Expression, error) {
	left, err := f.Left.TransformUp(fn)
	if err != nil {
		return nil, err
	}

	var right sql.Expression
	if f.Right != nil {
		right, err = f.Right.TransformUp(fn)
		if err != nil {
			return nil, err
		}
	}

	return fn(&Language{left, right})
}

// Eval implements the Expression interface.
func (f *Language) Eval(ctx *sql.Context, row sql.Row) (interface{}, error) {
	span, ctx := ctx.Span("gitbase.Language")
	defer span.Finish()

	left, err := f.Left.Eval(ctx, row)
	if err != nil {
		return nil, err
	}

	if left == nil {
		return nil, nil
	}

	left, err = sql.Text.Convert(left)
	if err != nil {
		return nil, err
	}

	path := left.(string)
	var blob []byte

	if f.Right != nil {
		right, err := f.Right.Eval(ctx, row)
		if err != nil {
			return nil, err
		}

		if right == nil {
			return nil, nil
		}

		right, err = sql.Blob.Convert(right)
		if err != nil {
			return nil, err
		}

		blob = right.([]byte)
	}

	if lang := enry.GetLanguage(path, blob); lang != "" {
		return lang, nil
	}

	return nil, nil
}

// Children implements the Expression interface.
func (f *Language) Children() []sql.Expression {
	if f.Right == nil {
		return []sql.Expression{f.Left}
	}

	return []sql.Expression{f.Left, f.Right}
}
<commit_msg>internal/function: use cache for expensive language operations<commit_after>package function

import (
	"encoding/binary"
	"fmt"
	"hash/crc32"

	lru "github.com/hashicorp/golang-lru"
	enry "gopkg.in/src-d/enry.v1"
	"gopkg.in/src-d/go-mysql-server.v0/sql"
)

const defaultLanguageCacheSize = 10000

var languageCache *lru.TwoQueueCache

func init() {
	var err error
	languageCache, err = lru.New2Q(defaultLanguageCacheSize)
	if err != nil {
		panic(fmt.Errorf("cannot initialize language cache: %s", err))
	}
}

// Language gets the language of a file given its path and
// the optional content of the file.
type Language struct {
	Left  sql.Expression
	Right sql.Expression
}

// NewLanguage creates a new Language UDF.
func NewLanguage(args ...sql.Expression) (sql.Expression, error) {
	var left, right sql.Expression
	switch len(args) {
	case 1:
		left = args[0]
	case 2:
		left = args[0]
		right = args[1]
	default:
		return nil, sql.ErrInvalidArgumentNumber.New("1 or 2", len(args))
	}

	return &Language{left, right}, nil
}

// Resolved implements the Expression interface.
func (f *Language) Resolved() bool {
	return f.Left.Resolved() && (f.Right == nil || f.Right.Resolved())
}

func (f *Language) String() string {
	if f.Right == nil {
		return fmt.Sprintf("language(%s)", f.Left)
	}
	return fmt.Sprintf("language(%s, %s)", f.Left, f.Right)
}

// IsNullable implements the Expression interface.
func (f *Language) IsNullable() bool {
	return f.Left.IsNullable() || (f.Right != nil && f.Right.IsNullable())
}

// Type implements the Expression interface.
func (Language) Type() sql.Type {
	return sql.Text
}

// TransformUp implements the Expression interface.
func (f *Language) TransformUp(fn sql.TransformExprFunc) (sql.Expression, error) {
	left, err := f.Left.TransformUp(fn)
	if err != nil {
		return nil, err
	}

	var right sql.Expression
	if f.Right != nil {
		right, err = f.Right.TransformUp(fn)
		if err != nil {
			return nil, err
		}
	}

	return fn(&Language{left, right})
}

// Eval implements the Expression interface.
func (f *Language) Eval(ctx *sql.Context, row sql.Row) (interface{}, error) {
	span, ctx := ctx.Span("gitbase.Language")
	defer span.Finish()

	left, err := f.Left.Eval(ctx, row)
	if err != nil {
		return nil, err
	}

	if left == nil {
		return nil, nil
	}

	left, err = sql.Text.Convert(left)
	if err != nil {
		return nil, err
	}

	path := left.(string)
	var blob []byte

	if f.Right != nil {
		right, err := f.Right.Eval(ctx, row)
		if err != nil {
			return nil, err
		}

		if right == nil {
			return nil, nil
		}

		right, err = sql.Blob.Convert(right)
		if err != nil {
			return nil, err
		}

		blob = right.([]byte)
	}

	var hash [8]byte
	if len(blob) > 0 {
		hash = languageHash(path, blob)
		value, ok := languageCache.Get(hash)
		if ok {
			return value, nil
		}
	}

	lang := enry.GetLanguage(path, blob)
	if lang == "" {
		return nil, nil
	}

	if len(blob) > 0 {
		languageCache.Add(hash, lang)
	}

	return lang, nil
}

func languageHash(filename string, blob []byte) [8]byte {
	fh := filenameHash(filename)
	bh := blobHash(blob)

	var result [8]byte
	copy(result[:], fh)
	copy(result[4:], bh)
	return result
}

const blobPeekSize = 40

func blobHash(blob []byte) []byte {
	if len(blob) == 0 {
		return nil
	}

	var result []byte
	if len(blob) < blobPeekSize*2 {
		result = blob
	} else {
		result = make([]byte, 0, blobPeekSize*2)
		result = append(result, blob[:blobPeekSize]...)
		result = append(result, blob[len(blob)-blobPeekSize:]...)
	}

	n := crc32.ChecksumIEEE(result)
	hash := make([]byte, 4)
	binary.LittleEndian.PutUint32(hash, n)
	return hash
}

func filenameHash(filename string) []byte {
	n := crc32.ChecksumIEEE([]byte(filename))
	hash := make([]byte, 4)
	binary.LittleEndian.PutUint32(hash, n)
	return hash
}

// Children implements the Expression interface.
func (f *Language) Children() []sql.Expression {
	if f.Right == nil {
		return []sql.Expression{f.Left}
	}

	return []sql.Expression{f.Left, f.Right}
}
<|endoftext|>


<commit_before>// Copyright 2017 The Ebiten Authors
//
// 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.

package graphics

var (
	theVerticesBackend = &verticesBackend{}
)

type verticesBackend struct {
	backend []float32
	head    int
}

const (
	IndicesNum     = (1 << 16) / 3 * 3 // Adjust num for triangles.
	VertexFloatNum = 12
)

func (v *verticesBackend) slice(n int) []float32 {
	const num = 1024
	if n > num {
		panic("not reached")
	}

	need := n * VertexFloatNum
	if v.head+need > len(v.backend) {
		v.backend = nil
		v.head = 0
	}

	if v.backend == nil {
		v.backend = make([]float32, VertexFloatNum*num)
	}

	s := v.backend[v.head : v.head+need]
	v.head += need
	return s
}

func isPowerOf2(x int) bool {
	if x <= 0 {
		return false
	}
	return (x & (x - 1)) == 0
}

func QuadVertices(width, height int, sx0, sy0, sx1, sy1 int, a, b, c, d, tx, ty float32, cr, cg, cb, ca float32) []float32 {
	if !isPowerOf2(width) {
		panic("not reached")
	}
	if !isPowerOf2(height) {
		panic("not reached")
	}

	if sx0 >= sx1 || sy0 >= sy1 {
		return nil
	}
	if sx1 <= 0 || sy1 <= 0 {
		return nil
	}

	wf := float32(width)
	hf := float32(height)
	u0, v0, u1, v1 := float32(sx0)/wf, float32(sy0)/hf, float32(sx1)/wf, float32(sy1)/hf
	return quadVerticesImpl(float32(sx1-sx0), float32(sy1-sy0), u0, v0, u1, v1, a, b, c, d, tx, ty, cr, cg, cb, ca)
}

func quadVerticesImpl(x, y, u0, v0, u1, v1, a, b, c, d, tx, ty, cr, cg, cb, ca float32) []float32 {
	// Specifying a range explicitly here is redundant but this helps optimization
	// to eliminate boundary checks.
	//
	// 4*VertexFloatNum is better than 48, but in GopherJS, optimization might not work.
	vs := theVerticesBackend.slice(4)[0:48]

	ax, by, cx, dy := a*x, b*y, c*x, d*y

	// Vertex coordinates
	vs[0] = tx
	vs[1] = ty

	// Texture coordinates: first 2 values indicates the actual coodinate, and
	// the second indicates diagonally opposite coodinates.
	// The second is needed to calculate source rectangle size in shader programs.
	vs[2] = u0
	vs[3] = v0
	vs[4] = u0
	vs[5] = v0
	vs[6] = u1
	vs[7] = v1
	vs[8] = cr
	vs[9] = cg
	vs[10] = cb
	vs[11] = ca

	// and the same for the other three coordinates
	vs[12] = ax + tx
	vs[13] = cx + ty
	vs[14] = u1
	vs[15] = v0
	vs[16] = u0
	vs[17] = v0
	vs[18] = u1
	vs[19] = v1
	vs[20] = cr
	vs[21] = cg
	vs[22] = cb
	vs[23] = ca

	vs[24] = by + tx
	vs[25] = dy + ty
	vs[26] = u0
	vs[27] = v1
	vs[28] = u0
	vs[29] = v0
	vs[30] = u1
	vs[31] = v1
	vs[32] = cr
	vs[33] = cg
	vs[34] = cb
	vs[35] = ca

	vs[36] = ax + by + tx
	vs[37] = cx + dy + ty
	vs[38] = u1
	vs[39] = v1
	vs[40] = u0
	vs[41] = v0
	vs[42] = u1
	vs[43] = v1
	vs[44] = cr
	vs[45] = cg
	vs[46] = cb
	vs[47] = ca

	return vs
}

var (
	quadIndices = []uint16{0, 1, 2, 1, 2, 3}
)

func QuadIndices() []uint16 {
	return quadIndices
}

func PutVertex(vs []float32, width, height int, dx, dy, su, sv float32, u0, v0, u1, v1 float32, cr, cg, cb, ca float32) {
	if !isPowerOf2(width) {
		panic("not reached")
	}
	if !isPowerOf2(height) {
		panic("not reached")
	}

	vs[0] = dx
	vs[1] = dy
	vs[2] = su
	vs[3] = sv
	vs[4] = u0
	vs[5] = v0
	vs[6] = u1
	vs[7] = v1
	vs[8] = cr
	vs[9] = cg
	vs[10] = cb
	vs[11] = ca
}
<commit_msg>graphics: Make verticesBackend concurrent safe<commit_after>// Copyright 2017 The Ebiten Authors
//
// 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.

package graphics

import (
	"sync"
)

var (
	theVerticesBackend = &verticesBackend{}
)

type verticesBackend struct {
	backend []float32
	head    int
	m       sync.Mutex
}

const (
	IndicesNum     = (1 << 16) / 3 * 3 // Adjust num for triangles.
	VertexFloatNum = 12
)

func (v *verticesBackend) slice(n int) []float32 {
	const num = 1024
	if n > num {
		panic("not reached")
	}

	v.m.Lock()

	need := n * VertexFloatNum
	if v.head+need > len(v.backend) {
		v.backend = nil
		v.head = 0
	}

	if v.backend == nil {
		v.backend = make([]float32, VertexFloatNum*num)
	}

	s := v.backend[v.head : v.head+need]
	v.head += need

	v.m.Unlock()
	return s
}

func isPowerOf2(x int) bool {
	if x <= 0 {
		return false
	}
	return (x & (x - 1)) == 0
}

func QuadVertices(width, height int, sx0, sy0, sx1, sy1 int, a, b, c, d, tx, ty float32, cr, cg, cb, ca float32) []float32 {
	if !isPowerOf2(width) {
		panic("not reached")
	}
	if !isPowerOf2(height) {
		panic("not reached")
	}

	if sx0 >= sx1 || sy0 >= sy1 {
		return nil
	}
	if sx1 <= 0 || sy1 <= 0 {
		return nil
	}

	wf := float32(width)
	hf := float32(height)
	u0, v0, u1, v1 := float32(sx0)/wf, float32(sy0)/hf, float32(sx1)/wf, float32(sy1)/hf
	return quadVerticesImpl(float32(sx1-sx0), float32(sy1-sy0), u0, v0, u1, v1, a, b, c, d, tx, ty, cr, cg, cb, ca)
}

func quadVerticesImpl(x, y, u0, v0, u1, v1, a, b, c, d, tx, ty, cr, cg, cb, ca float32) []float32 {
	// Specifying a range explicitly here is redundant but this helps optimization
	// to eliminate boundary checks.
	//
	// 4*VertexFloatNum is better than 48, but in GopherJS, optimization might not work.
	vs := theVerticesBackend.slice(4)[0:48]

	ax, by, cx, dy := a*x, b*y, c*x, d*y

	// Vertex coordinates
	vs[0] = tx
	vs[1] = ty

	// Texture coordinates: first 2 values indicates the actual coodinate, and
	// the second indicates diagonally opposite coodinates.
	// The second is needed to calculate source rectangle size in shader programs.
	vs[2] = u0
	vs[3] = v0
	vs[4] = u0
	vs[5] = v0
	vs[6] = u1
	vs[7] = v1
	vs[8] = cr
	vs[9] = cg
	vs[10] = cb
	vs[11] = ca

	// and the same for the other three coordinates
	vs[12] = ax + tx
	vs[13] = cx + ty
	vs[14] = u1
	vs[15] = v0
	vs[16] = u0
	vs[17] = v0
	vs[18] = u1
	vs[19] = v1
	vs[20] = cr
	vs[21] = cg
	vs[22] = cb
	vs[23] = ca

	vs[24] = by + tx
	vs[25] = dy + ty
	vs[26] = u0
	vs[27] = v1
	vs[28] = u0
	vs[29] = v0
	vs[30] = u1
	vs[31] = v1
	vs[32] = cr
	vs[33] = cg
	vs[34] = cb
	vs[35] = ca

	vs[36] = ax + by + tx
	vs[37] = cx + dy + ty
	vs[38] = u1
	vs[39] = v1
	vs[40] = u0
	vs[41] = v0
	vs[42] = u1
	vs[43] = v1
	vs[44] = cr
	vs[45] = cg
	vs[46] = cb
	vs[47] = ca

	return vs
}

var (
	quadIndices = []uint16{0, 1, 2, 1, 2, 3}
)

func QuadIndices() []uint16 {
	return quadIndices
}

func PutVertex(vs []float32, width, height int, dx, dy, su, sv float32, u0, v0, u1, v1 float32, cr, cg, cb, ca float32) {
	if !isPowerOf2(width) {
		panic("not reached")
	}
	if !isPowerOf2(height) {
		panic("not reached")
	}

	vs[0] = dx
	vs[1] = dy
	vs[2] = su
	vs[3] = sv
	vs[4] = u0
	vs[5] = v0
	vs[6] = u1
	vs[7] = v1
	vs[8] = cr
	vs[9] = cg
	vs[10] = cb
	vs[11] = ca
}
<|endoftext|>


<commit_before>package models

import (
	"fmt"
	"log"
	"strings"
	"time"

	"github.com/brnstz/bus/internal/conf"
	"github.com/brnstz/bus/internal/etc"
)

const (
	hereQueryLimit         = 10000
	departureLookaheadSecs = 60 * 60 * 3

	hereQuery = `
		SELECT
			agency_id,
			route_id,
			stop_id,
			service_id,
			trip_ids,
			arrival_secs,
			departure_secs,
			stop_sequences,
			next_stop_lats,
			next_stop_lons,

			stop_name,
			direction_id,
			stop_headsign,
			ST_X(location) AS lat,
			ST_Y(location) AS lon,

			route_type,
			route_color,
			route_text_color,
			route_short_name,
			route_long_name,

			trip_headsign,

			ST_DISTANCE(ST_GEOMFROMTEXT(:point_string, 4326), location) AS dist

		FROM here_trip

		WHERE
			ST_CONTAINS(ST_SETSRID(
				ST_MAKEPOLYGON(:line_string), 4326), location) AND

			(
				service_id IN (%s) OR
				service_id IN (%s) OR
				service_id IN (%s)
			)
	`

	routeTypeFilter = `
		AND route_type IN (%s)
	`

	hereOrderLimit = `
		ORDER BY dist ASC
		LIMIT :limit
	`
)

type HereQuery struct {
	// The southwest and northeast bounding points of the box we are
	// searching
	SWLat float64 `db:"sw_lat"`
	SWLon float64 `db:"sw_lon"`
	NELat float64 `db:"ne_lat"`
	NELon float64 `db:"ne_lon"`

	// The midpoint of our search box
	MidLat float64 `db:"mid_lat"`
	MidLon float64 `db:"mid_lon"`

	LineString  string `db:"line_string"`
	PointString string `db:"point_string"`

	YesterdayDepartureMin  int
	YesterdayDepartureMax  int
	YesterdaySecDiff       int
	YesterdayDepartureBase time.Time
	YesterdayServiceIDs    []string
	YesterdayRelevantIDs   map[string]bool

	TodayDepartureMin  int
	TodayDepartureMax  int
	TodayDepartureBase time.Time
	TodayServiceIDs    []string
	TodayRelevantIDs   map[string]bool

	TomorrowDepartureMin  int
	TomorrowDepartureMax  int
	TomorrowSecDiff       int
	TomorrowDepartureBase time.Time
	TomorrowServiceIDs    []string
	TomorrowRelevantIDs   map[string]bool

	Limit int `db:"limit"`

	Query string
}

func NewHereQuery(lat, lon, swlat, swlon, nelat, nelon float64, routeTypes []int, now time.Time) (hq *HereQuery, err error) {

	// FIXME: hard coded, we need a lat/lon to agencyID mapping
	agencyIDs := conf.Partner.AgencyIDs
	log.Println("here are the agency IDs", agencyIDs)

	today := etc.BaseTime(now)
	todayName := strings.ToLower(now.Format("Monday"))
	todayMinSec := etc.TimeToDepartureSecs(now)
	todayMaxSec := todayMinSec + departureLookaheadSecs
	todayServiceIDs, err := GetAgencyServiceIDs(etc.DBConn, agencyIDs, todayName, today)
	if err != nil {
		log.Println("can't get today serviceIDs", err)
		return
	}
	todayRelevantIDs, err := getRouteServiceIDs(etc.DBConn, agencyIDs, todayName, today)
	if err != nil {
		log.Println("can't get today relevent IDs", err)
		return
	}

	yesterday := today.AddDate(0, 0, -1)
	yesterdayName := strings.ToLower(yesterday.Format("Monday"))
	yesterdayMinSec := now.Hour()*3600 + now.Minute()*60 + now.Second() + midnightSecs
	yesterdayMaxSec := yesterdayMinSec + departureLookaheadSecs
	yesterdaySecDiff := int(today.Sub(yesterday).Seconds())
	yesterdayServiceIDs, err := GetAgencyServiceIDs(etc.DBConn, agencyIDs, yesterdayName, yesterday)
	if err != nil {
		log.Println("can't get yesterday serviceIDs", err)
		return
	}
	yesterdayRelevantIDs, err := getRouteServiceIDs(etc.DBConn, agencyIDs, yesterdayName, yesterday)
	if err != nil {
		log.Println("can't get yesterday relevent IDs", err)
		return
	}

	tomorrow := today.AddDate(0, 0, 1)
	tomorrowName := strings.ToLower(tomorrow.Format("Monday"))
	tomorrowMinSec := 0
	tomorrowMaxSec := departureLookaheadSecs
	tomorrowSecDiff := int(tomorrow.Sub(today).Seconds())
	tomorrowServiceIDs, err := GetAgencyServiceIDs(etc.DBConn, agencyIDs, tomorrowName, tomorrow)
	if err != nil {
		log.Println("can't get tomorrow serviceIDs", err)
		return
	}
	tomorrowRelevantIDs, err := getRouteServiceIDs(etc.DBConn, agencyIDs, tomorrowName, tomorrow)
	if err != nil {
		log.Println("can't get tomorrow relevent IDs", err)
		return
	}

	// Check for overlap. If there is overlap, then nullify that day in
	// preference for today.
	if yesterdayMinSec <= todayMaxSec && todayMinSec <= yesterdayMaxSec {
		yesterdayMinSec = -1
		yesterdayMaxSec = -1
	}

	if tomorrowMinSec <= todayMaxSec && todayMinSec <= tomorrowMaxSec {
		tomorrowMinSec = -1
		tomorrowMaxSec = -1
	}

	// Check that yesterday is relevant
	if todayMinSec > departureLookaheadSecs {
		yesterdayMinSec = -1
		yesterdayMaxSec = -1
	}

	// Check that tomorrow is relevant
	if todayMaxSec < midnightSecs {
		tomorrowMinSec = -1
		tomorrowMaxSec = -1
	}

	hq = &HereQuery{
		MidLat: lat,
		MidLon: lon,
		SWLat:  swlat,
		SWLon:  swlon,
		NELat:  nelat,
		NELon:  nelon,
		Limit:  hereQueryLimit,

		TodayServiceIDs:    todayServiceIDs,
		TodayDepartureMin:  todayMinSec,
		TodayDepartureMax:  todayMaxSec,
		TodayDepartureBase: today,
		TodayRelevantIDs:   todayRelevantIDs,

		YesterdayServiceIDs:    yesterdayServiceIDs,
		YesterdayDepartureMin:  yesterdayMinSec,
		YesterdayDepartureMax:  yesterdayMaxSec,
		YesterdayDepartureBase: yesterday,
		YesterdaySecDiff:       yesterdaySecDiff,
		YesterdayRelevantIDs:   yesterdayRelevantIDs,

		TomorrowServiceIDs:    tomorrowServiceIDs,
		TomorrowDepartureMin:  tomorrowMinSec,
		TomorrowDepartureMax:  tomorrowMaxSec,
		TomorrowDepartureBase: tomorrow,
		TomorrowSecDiff:       tomorrowSecDiff,
		TomorrowRelevantIDs:   tomorrowRelevantIDs,
	}

	hq.LineString = fmt.Sprintf(
		`LINESTRING(%f %f, %f %f, %f %f, %f %f, %f %f)`,
		hq.SWLat, hq.SWLon,
		hq.SWLat, hq.NELon,
		hq.NELat, hq.NELon,
		hq.NELat, hq.SWLon,
		hq.SWLat, hq.SWLon,
	)

	hq.PointString = fmt.Sprintf(
		`POINT(%f %f)`,
		hq.MidLat, hq.MidLon,
	)

	hq.Query = fmt.Sprintf(hereQuery,
		etc.CreateIDs(hq.YesterdayServiceIDs),
		etc.CreateIDs(hq.TodayServiceIDs),
		etc.CreateIDs(hq.TomorrowServiceIDs),
	)

	if len(routeTypes) > 0 {
		hq.Query = hq.Query + fmt.Sprintf(routeTypeFilter, etc.CreateIntIDs(routeTypes))
	}

	hq.Query = hq.Query + hereOrderLimit

	return
}
<commit_msg>remove agency ids<commit_after>package models

import (
	"fmt"
	"log"
	"strings"
	"time"

	"github.com/brnstz/bus/internal/conf"
	"github.com/brnstz/bus/internal/etc"
)

const (
	hereQueryLimit         = 10000
	departureLookaheadSecs = 60 * 60 * 3

	hereQuery = `
		SELECT
			agency_id,
			route_id,
			stop_id,
			service_id,
			trip_ids,
			arrival_secs,
			departure_secs,
			stop_sequences,
			next_stop_lats,
			next_stop_lons,

			stop_name,
			direction_id,
			stop_headsign,
			ST_X(location) AS lat,
			ST_Y(location) AS lon,

			route_type,
			route_color,
			route_text_color,
			route_short_name,
			route_long_name,

			trip_headsign,

			ST_DISTANCE(ST_GEOMFROMTEXT(:point_string, 4326), location) AS dist

		FROM here_trip

		WHERE
			ST_CONTAINS(ST_SETSRID(
				ST_MAKEPOLYGON(:line_string), 4326), location) AND

			(
				service_id IN (%s) OR
				service_id IN (%s) OR
				service_id IN (%s)
			)
	`

	routeTypeFilter = `
		AND route_type IN (%s)
	`

	hereOrderLimit = `
		ORDER BY dist ASC
		LIMIT :limit
	`
)

type HereQuery struct {
	// The southwest and northeast bounding points of the box we are
	// searching
	SWLat float64 `db:"sw_lat"`
	SWLon float64 `db:"sw_lon"`
	NELat float64 `db:"ne_lat"`
	NELon float64 `db:"ne_lon"`

	// The midpoint of our search box
	MidLat float64 `db:"mid_lat"`
	MidLon float64 `db:"mid_lon"`

	LineString  string `db:"line_string"`
	PointString string `db:"point_string"`

	YesterdayDepartureMin  int
	YesterdayDepartureMax  int
	YesterdaySecDiff       int
	YesterdayDepartureBase time.Time
	YesterdayServiceIDs    []string
	YesterdayRelevantIDs   map[string]bool

	TodayDepartureMin  int
	TodayDepartureMax  int
	TodayDepartureBase time.Time
	TodayServiceIDs    []string
	TodayRelevantIDs   map[string]bool

	TomorrowDepartureMin  int
	TomorrowDepartureMax  int
	TomorrowSecDiff       int
	TomorrowDepartureBase time.Time
	TomorrowServiceIDs    []string
	TomorrowRelevantIDs   map[string]bool

	Limit int `db:"limit"`

	Query string
}

func NewHereQuery(lat, lon, swlat, swlon, nelat, nelon float64, routeTypes []int, now time.Time) (hq *HereQuery, err error) {

	// FIXME: hard coded, we need a lat/lon to agencyID mapping
	agencyIDs := conf.Partner.AgencyIDs

	today := etc.BaseTime(now)
	todayName := strings.ToLower(now.Format("Monday"))
	todayMinSec := etc.TimeToDepartureSecs(now)
	todayMaxSec := todayMinSec + departureLookaheadSecs
	todayServiceIDs, err := GetAgencyServiceIDs(etc.DBConn, agencyIDs, todayName, today)
	if err != nil {
		log.Println("can't get today serviceIDs", err)
		return
	}
	todayRelevantIDs, err := getRouteServiceIDs(etc.DBConn, agencyIDs, todayName, today)
	if err != nil {
		log.Println("can't get today relevent IDs", err)
		return
	}

	yesterday := today.AddDate(0, 0, -1)
	yesterdayName := strings.ToLower(yesterday.Format("Monday"))
	yesterdayMinSec := now.Hour()*3600 + now.Minute()*60 + now.Second() + midnightSecs
	yesterdayMaxSec := yesterdayMinSec + departureLookaheadSecs
	yesterdaySecDiff := int(today.Sub(yesterday).Seconds())
	yesterdayServiceIDs, err := GetAgencyServiceIDs(etc.DBConn, agencyIDs, yesterdayName, yesterday)
	if err != nil {
		log.Println("can't get yesterday serviceIDs", err)
		return
	}
	yesterdayRelevantIDs, err := getRouteServiceIDs(etc.DBConn, agencyIDs, yesterdayName, yesterday)
	if err != nil {
		log.Println("can't get yesterday relevent IDs", err)
		return
	}

	tomorrow := today.AddDate(0, 0, 1)
	tomorrowName := strings.ToLower(tomorrow.Format("Monday"))
	tomorrowMinSec := 0
	tomorrowMaxSec := departureLookaheadSecs
	tomorrowSecDiff := int(tomorrow.Sub(today).Seconds())
	tomorrowServiceIDs, err := GetAgencyServiceIDs(etc.DBConn, agencyIDs, tomorrowName, tomorrow)
	if err != nil {
		log.Println("can't get tomorrow serviceIDs", err)
		return
	}
	tomorrowRelevantIDs, err := getRouteServiceIDs(etc.DBConn, agencyIDs, tomorrowName, tomorrow)
	if err != nil {
		log.Println("can't get tomorrow relevent IDs", err)
		return
	}

	// Check for overlap. If there is overlap, then nullify that day in
	// preference for today.
	if yesterdayMinSec <= todayMaxSec && todayMinSec <= yesterdayMaxSec {
		yesterdayMinSec = -1
		yesterdayMaxSec = -1
	}

	if tomorrowMinSec <= todayMaxSec && todayMinSec <= tomorrowMaxSec {
		tomorrowMinSec = -1
		tomorrowMaxSec = -1
	}

	// Check that yesterday is relevant
	if todayMinSec > departureLookaheadSecs {
		yesterdayMinSec = -1
		yesterdayMaxSec = -1
	}

	// Check that tomorrow is relevant
	if todayMaxSec < midnightSecs {
		tomorrowMinSec = -1
		tomorrowMaxSec = -1
	}

	hq = &HereQuery{
		MidLat: lat,
		MidLon: lon,
		SWLat:  swlat,
		SWLon:  swlon,
		NELat:  nelat,
		NELon:  nelon,
		Limit:  hereQueryLimit,

		TodayServiceIDs:    todayServiceIDs,
		TodayDepartureMin:  todayMinSec,
		TodayDepartureMax:  todayMaxSec,
		TodayDepartureBase: today,
		TodayRelevantIDs:   todayRelevantIDs,

		YesterdayServiceIDs:    yesterdayServiceIDs,
		YesterdayDepartureMin:  yesterdayMinSec,
		YesterdayDepartureMax:  yesterdayMaxSec,
		YesterdayDepartureBase: yesterday,
		YesterdaySecDiff:       yesterdaySecDiff,
		YesterdayRelevantIDs:   yesterdayRelevantIDs,

		TomorrowServiceIDs:    tomorrowServiceIDs,
		TomorrowDepartureMin:  tomorrowMinSec,
		TomorrowDepartureMax:  tomorrowMaxSec,
		TomorrowDepartureBase: tomorrow,
		TomorrowSecDiff:       tomorrowSecDiff,
		TomorrowRelevantIDs:   tomorrowRelevantIDs,
	}

	hq.LineString = fmt.Sprintf(
		`LINESTRING(%f %f, %f %f, %f %f, %f %f, %f %f)`,
		hq.SWLat, hq.SWLon,
		hq.SWLat, hq.NELon,
		hq.NELat, hq.NELon,
		hq.NELat, hq.SWLon,
		hq.SWLat, hq.SWLon,
	)

	hq.PointString = fmt.Sprintf(
		`POINT(%f %f)`,
		hq.MidLat, hq.MidLon,
	)

	hq.Query = fmt.Sprintf(hereQuery,
		etc.CreateIDs(hq.YesterdayServiceIDs),
		etc.CreateIDs(hq.TodayServiceIDs),
		etc.CreateIDs(hq.TomorrowServiceIDs),
	)

	if len(routeTypes) > 0 {
		hq.Query = hq.Query + fmt.Sprintf(routeTypeFilter, etc.CreateIntIDs(routeTypes))
	}

	hq.Query = hq.Query + hereOrderLimit

	return
}
<|endoftext|>


<commit_before>package x86_test

import (
	"bufio"
	"bytes"
	"fmt"
	"internal/testenv"
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
	"regexp"
	"strconv"
	"strings"
	"testing"
)

const testdata = `
MOVQ AX, AX -> MOVQ AX, AX

LEAQ name(SB), AX -> MOVQ name@GOT(SB), AX
LEAQ name+10(SB), AX -> MOVQ name@GOT(SB), AX; LEAQ 10(AX), AX
MOVQ $name(SB), AX -> MOVQ name@GOT(SB), AX
MOVQ $name+10(SB), AX -> MOVQ name@GOT(SB), AX; LEAQ 10(AX), AX

MOVQ name(SB), AX -> NOP; MOVQ name@GOT(SB), R15; MOVQ (R15), AX
MOVQ name+10(SB), AX -> NOP; MOVQ name@GOT(SB), R15; MOVQ 10(R15), AX

CMPQ name(SB), $0 -> NOP; MOVQ name@GOT(SB), R15; CMPQ (R15), $0

MOVQ $1, name(SB) -> NOP; MOVQ name@GOT(SB), R15; MOVQ $1, (R15)
MOVQ $1, name+10(SB) -> NOP; MOVQ name@GOT(SB), R15; MOVQ $1, 10(R15)
`

type ParsedTestData struct {
	input              string
	marks              []int
	marker_to_input    map[int][]string
	marker_to_expected map[int][]string
	marker_to_output   map[int][]string
}

const marker_start = 1234

func parseTestData(t *testing.T) *ParsedTestData {
	r := &ParsedTestData{}
	scanner := bufio.NewScanner(strings.NewReader(testdata))
	r.marker_to_input = make(map[int][]string)
	r.marker_to_expected = make(map[int][]string)
	marker := marker_start
	input_insns := []string{}
	for scanner.Scan() {
		line := scanner.Text()
		if len(strings.TrimSpace(line)) == 0 {
			continue
		}
		parts := strings.Split(line, "->")
		if len(parts) != 2 {
			t.Fatalf("malformed line %v", line)
		}
		r.marks = append(r.marks, marker)
		marker_insn := fmt.Sprintf("MOVQ $%d, AX", marker)
		input_insns = append(input_insns, marker_insn)
		for _, input_insn := range strings.Split(parts[0], ";") {
			input_insns = append(input_insns, input_insn)
			r.marker_to_input[marker] = append(r.marker_to_input[marker], normalize(input_insn))
		}
		for _, expected_insn := range strings.Split(parts[1], ";") {
			r.marker_to_expected[marker] = append(r.marker_to_expected[marker], normalize(expected_insn))
		}
		marker++
	}
	r.input = "TEXT ·foo(SB),$0\n" + strings.Join(input_insns, "\n") + "\n"
	return r
}

var spaces_re *regexp.Regexp = regexp.MustCompile("\\s+")

func normalize(s string) string {
	return spaces_re.ReplaceAllLiteralString(strings.TrimSpace(s), " ")
}

func asmOutput(t *testing.T, s string) []byte {
	tmpdir, err := ioutil.TempDir("", "progedittest")
	if err != nil {
		t.Fatal(err)
	}
	defer os.RemoveAll(tmpdir)
	tmpfile, err := os.Create(filepath.Join(tmpdir, "input.s"))
	if err != nil {
		t.Fatal(err)
	}
	defer tmpfile.Close()
	_, err = tmpfile.WriteString(s)
	if err != nil {
		t.Fatal(err)
	}
	cmd := exec.Command(
		testenv.GoToolPath(t), "tool", "asm", "-S", "-dynlink",
		"-o", filepath.Join(tmpdir, "output.6"), tmpfile.Name())

	var env []string
	for _, v := range os.Environ() {
		if !strings.HasPrefix(v, "GOARCH=") {
			env = append(env, v)
		}
	}
	cmd.Env = append(env, "GOARCH=amd64")
	asmout, err := cmd.CombinedOutput()
	if err != nil {
		t.Fatalf("error %s output %s", err, asmout)
	}
	return asmout
}

func parseOutput(t *testing.T, td *ParsedTestData, asmout []byte) {
	scanner := bufio.NewScanner(bytes.NewReader(asmout))
	marker := regexp.MustCompile("MOVQ \\$([0-9]+), AX")
	mark := -1
	td.marker_to_output = make(map[int][]string)
	for scanner.Scan() {
		line := scanner.Text()
		if line[0] != '\t' {
			continue
		}
		parts := strings.SplitN(line, "\t", 3)
		if len(parts) != 3 {
			continue
		}
		n := normalize(parts[2])
		mark_matches := marker.FindStringSubmatch(n)
		if mark_matches != nil {
			mark, _ = strconv.Atoi(mark_matches[1])
			if _, ok := td.marker_to_input[mark]; !ok {
				t.Fatalf("unexpected marker %d", mark)
			}
		} else if mark != -1 {
			td.marker_to_output[mark] = append(td.marker_to_output[mark], n)
		}
	}
}

func TestDynlink(t *testing.T) {
	testenv.MustHaveGoBuild(t)

	if os.Getenv("GOHOSTARCH") != "" {
		// TODO: make this work? It was failing due to the
		// GOARCH= filtering above and skipping is easiest for
		// now.
		t.Skip("skipping when GOHOSTARCH is set")
	}

	testdata := parseTestData(t)
	asmout := asmOutput(t, testdata.input)
	parseOutput(t, testdata, asmout)
	for _, m := range testdata.marks {
		i := strings.Join(testdata.marker_to_input[m], "; ")
		o := strings.Join(testdata.marker_to_output[m], "; ")
		e := strings.Join(testdata.marker_to_expected[m], "; ")
		if o != e {
			if o == i {
				t.Errorf("%s was unchanged; should have become %s", i, e)
			} else {
				t.Errorf("%s became %s; should have become %s", i, o, e)
			}
		} else if i != e {
			t.Logf("%s correctly became %s", i, o)
		}
	}
}
<commit_msg>remove the test that required internal/testenv<commit_after><|endoftext|>


<commit_before>// Copyright 2015 The Vanadium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Daemon groupsd implements the v.io/v23/services/groups interfaces for
// managing access control groups.
package main

// Example invocation:
// groupsd --v23.tcp.address="127.0.0.1:0" --name=groupsd

import (
	"flag"

	"v.io/v23"
	"v.io/v23/security"
	"v.io/v23/security/access"
	"v.io/x/lib/vlog"
	"v.io/x/ref/lib/security/securityflag"
	"v.io/x/ref/lib/signals"
	"v.io/x/ref/lib/xrpc"
	_ "v.io/x/ref/runtime/factories/generic"
	"v.io/x/ref/services/groups/internal/server"
	"v.io/x/ref/services/groups/internal/store/memstore"
)

var (
	name = flag.String("name", "", "Name to mount at.")
)

// defaultPerms returns a permissions object that grants all permissions to the
// provided blessing patterns.
func defaultPerms(blessingPatterns []security.BlessingPattern) access.Permissions {
	perms := access.Permissions{}
	for _, tag := range access.AllTypicalTags() {
		for _, bp := range blessingPatterns {
			perms.Add(bp, string(tag))
		}
	}
	return perms
}

// TODO(ashankar, jsimsa): Implement groupsd using the cmdline package.
func main() {
	ctx, shutdown := v23.Init()
	defer shutdown()

	perms, err := securityflag.PermissionsFromFlag()
	if err != nil {
		vlog.Fatal("securityflag.PermissionsFromFlag() failed: ", err)
	}

	if perms != nil {
		vlog.Info("Using permissions from command line flag.")
	} else {
		vlog.Info("No permissions flag provided. Giving local principal all permissions.")
		perms = defaultPerms(security.DefaultBlessingPatterns(v23.GetPrincipal(ctx)))
	}

	m := server.NewManager(memstore.New(), perms)
	if _, err = xrpc.NewDispatchingServer(ctx, *name, m); err != nil {
		vlog.Fatal("NewDispatchingServer() failed: ", err)
	}
	vlog.Info("Mounted at: ", *name)

	// Wait forever.
	<-signals.ShutdownOnSignals(ctx)
}
<commit_msg>ref/services/groups: porting the groups daemon to the cmdline package<commit_after>// Copyright 2015 The Vanadium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Daemon groupsd implements the v.io/v23/services/groups interfaces for
// managing access control groups.
package main

// Example invocation:
// groupsd --v23.tcp.address="127.0.0.1:0" --name=groupsd

import (
	"fmt"

	"v.io/v23"
	"v.io/v23/context"
	"v.io/v23/security"
	"v.io/v23/security/access"
	"v.io/x/lib/cmdline"
	"v.io/x/ref/lib/security/securityflag"
	"v.io/x/ref/lib/signals"
	"v.io/x/ref/lib/v23cmd"
	"v.io/x/ref/lib/xrpc"
	_ "v.io/x/ref/runtime/factories/generic"
	"v.io/x/ref/services/groups/internal/server"
	"v.io/x/ref/services/groups/internal/store/memstore"
)

var flagName string

func main() {
	cmdGroupsD.Flags.StringVar(&flagName, "name", "", "Name to mount the groups server as.")

	cmdline.HideGlobalFlagsExcept()
	cmdline.Main(cmdGroupsD)
}

// defaultPerms returns a permissions object that grants all permissions to the
// provided blessing patterns.
func defaultPerms(blessingPatterns []security.BlessingPattern) access.Permissions {
	perms := access.Permissions{}
	for _, tag := range access.AllTypicalTags() {
		for _, bp := range blessingPatterns {
			perms.Add(bp, string(tag))
		}
	}
	return perms
}

var cmdGroupsD = &cmdline.Command{
	Runner: v23cmd.RunnerFunc(runGroupsD),
	Name:   "groupsd",
	Short:  "Runs the groups daemon.",
	Long: `
Command groupsd runs the groups daemon, which implements the
v.io/v23/services/groups.Group interface.
`,
}

func runGroupsD(ctx *context.T, env *cmdline.Env, args []string) error {
	perms, err := securityflag.PermissionsFromFlag()
	if err != nil {
		return fmt.Errorf("PermissionsFromFlag() failed: %v", err)
	}
	if perms != nil {
		ctx.Infof("Using permissions from command line flag.")
	} else {
		ctx.Infof("No permissions flag provided. Giving local principal all permissions.")
		perms = defaultPerms(security.DefaultBlessingPatterns(v23.GetPrincipal(ctx)))
	}
	m := server.NewManager(memstore.New(), perms)
	server, err := xrpc.NewDispatchingServer(ctx, flagName, m)
	if err != nil {
		fmt.Errorf("NewDispatchingServer(%v) failed: %v", flagName, err)
	}
	ctx.Infof("Groups server running at endpoint=%q", server.Status().Endpoints[0].Name())

	// Wait until shutdown.
	<-signals.ShutdownOnSignals(ctx)
	return nil
}
<|endoftext|>


<commit_before>// Copyright 2010 The go-pgsql Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package pgsql

//------------------------------------------------------------------------------

type backendMessageCode byte

const (
	_AuthenticationRequest backendMessageCode = 'R'
	_BackendKeyData        backendMessageCode = 'K'
	_BindComplete          backendMessageCode = '2'
	_CloseComplete         backendMessageCode = '3'
	_CommandComplete       backendMessageCode = 'C'
	_CopyData_BE           backendMessageCode = 'd'
	_CopyDone_BE           backendMessageCode = 'c'
	_CopyInResponse        backendMessageCode = 'G'
	_CopyOutResponse       backendMessageCode = 'H'
	_DataRow               backendMessageCode = 'D'
	_EmptyQueryResponse    backendMessageCode = 'I'
	_ErrorResponse         backendMessageCode = 'E'
	_FunctionCallResponse  backendMessageCode = 'V'
	_NoData                backendMessageCode = 'n'
	_NoticeResponse        backendMessageCode = 'N'
	_NotificationResponse  backendMessageCode = 'A'
	_ParameterDescription  backendMessageCode = 't'
	_ParameterStatus       backendMessageCode = 'S'
	_ParseComplete         backendMessageCode = '1'
	_PortalSuspended       backendMessageCode = 's'
	_ReadyForQuery         backendMessageCode = 'Z'
	_RowDescription        backendMessageCode = 'T'
)

var backendMsgCode2String map[backendMessageCode]string

func (x backendMessageCode) String() string {
	s, ok := backendMsgCode2String[x]
	if !ok {
		return "unkown backendMessageCode"
	}

	return s
}

//------------------------------------------------------------------------------

type frontendMessageCode byte

const (
	_Bind            frontendMessageCode = 'B'
	_Close           frontendMessageCode = 'C'
	_CopyData_FE     frontendMessageCode = 'd'
	_CopyDone_FE     frontendMessageCode = 'c'
	_CopyFail        frontendMessageCode = 'f'
	_Describe        frontendMessageCode = 'D'
	_Execute         frontendMessageCode = 'E'
	_Flush           frontendMessageCode = 'H'
	_FunctionCall    frontendMessageCode = 'F'
	_Parse           frontendMessageCode = 'P'
	_PasswordMessage frontendMessageCode = 'p'
	_Query           frontendMessageCode = 'Q'
	_SSLRequest      frontendMessageCode = '8'
	_Sync            frontendMessageCode = 'S'
	_Terminate       frontendMessageCode = 'X'
)

var frontendMsgCode2String map[frontendMessageCode]string

func (x frontendMessageCode) String() string {
	s, ok := frontendMsgCode2String[x]
	if !ok {
		return "unkown frontendMessageCode"
	}

	return s
}

//------------------------------------------------------------------------------

type authenticationType int32

const (
	_AuthenticationOk                authenticationType = 0
	_AuthenticationKerberosV5        authenticationType = 2
	_AuthenticationCleartextPassword authenticationType = 3
	_AuthenticationMD5Password       authenticationType = 5
	_AuthenticationSCMCredential     authenticationType = 6
	_AuthenticationGSS               authenticationType = 7
	_AuthenticationGSSContinue       authenticationType = 8
	_AuthenticationSSPI              authenticationType = 9
)

var authType2String map[authenticationType]string

func (x authenticationType) String() string {
	s, ok := authType2String[x]
	if !ok {
		return "unkown authenticationType"
	}

	return s
}

//------------------------------------------------------------------------------

func init() {

	backendMsgCode2String = make(map[backendMessageCode]string)

	backendMsgCode2String[_AuthenticationRequest] = "AuthenticationRequest"
	backendMsgCode2String[_BackendKeyData] = "BackendKeyData"
	backendMsgCode2String[_BindComplete] = "BindComplete"
	backendMsgCode2String[_CloseComplete] = "CloseComplete"
	backendMsgCode2String[_CommandComplete] = "CommandComplete"
	backendMsgCode2String[_CopyData_BE] = "CopyData"
	backendMsgCode2String[_CopyDone_BE] = "CopyDone"
	backendMsgCode2String[_CopyInResponse] = "CopyInResponse"
	backendMsgCode2String[_CopyOutResponse] = "CopyOutResponse"
	backendMsgCode2String[_DataRow] = "DataRow"
	backendMsgCode2String[_EmptyQueryResponse] = "EmptyQueryResponse"
	backendMsgCode2String[_ErrorResponse] = "ErrorResponse"
	backendMsgCode2String[_FunctionCallResponse] = "FunctionCallResponse"
	backendMsgCode2String[_NoData] = "NoData"
	backendMsgCode2String[_NoticeResponse] = "NoticeResponse"
	backendMsgCode2String[_NotificationResponse] = "NotificationResponse"
	backendMsgCode2String[_ParameterDescription] = "ParameterDescription"
	backendMsgCode2String[_ParameterStatus] = "ParameterStatus"
	backendMsgCode2String[_ParseComplete] = "ParseComplete"
	backendMsgCode2String[_PortalSuspended] = "PortalSuspended"
	backendMsgCode2String[_ReadyForQuery] = "ReadyForQuery"
	backendMsgCode2String[_RowDescription] = "RowDescription"

	//--------

	frontendMsgCode2String = make(map[frontendMessageCode]string)

	frontendMsgCode2String[_Bind] = "Bind"
	frontendMsgCode2String[_Close] = "Close"
	frontendMsgCode2String[_CopyData_FE] = "CopyData"
	frontendMsgCode2String[_CopyDone_FE] = "CopyDone"
	frontendMsgCode2String[_CopyFail] = "CopyFail"
	frontendMsgCode2String[_Describe] = "Describe"
	frontendMsgCode2String[_Execute] = "Execute"
	frontendMsgCode2String[_Flush] = "Flush"
	frontendMsgCode2String[_FunctionCall] = "FunctionCall"
	frontendMsgCode2String[_Parse] = "Parse"
	frontendMsgCode2String[_PasswordMessage] = "PasswordMessage"
	frontendMsgCode2String[_Query] = "Query"
	frontendMsgCode2String[_SSLRequest] = "SSLRequest"
	frontendMsgCode2String[_Sync] = "Sync"
	frontendMsgCode2String[_Terminate] = "Terminate"

	//--------

	authType2String = make(map[authenticationType]string)

	authType2String[_AuthenticationOk] = "AuthenticationOk"
	authType2String[_AuthenticationKerberosV5] = "AuthenticationKerberosV5"
	authType2String[_AuthenticationCleartextPassword] = "AuthenticationCleartextPassword"
	authType2String[_AuthenticationMD5Password] = "AuthenticationMD5Password"
	authType2String[_AuthenticationSCMCredential] = "AuthenticationSCMCredential"
	authType2String[_AuthenticationGSS] = "AuthenticationGSS"
	authType2String[_AuthenticationGSSContinue] = "AuthenticationGSSContinue"
	authType2String[_AuthenticationSSPI] = "AuthenticationSSPI"
}
<commit_msg>messagecodes: 'unk_own' typo, return unknown code itself<commit_after>// Copyright 2010 The go-pgsql Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package pgsql

import (
	"fmt"
)

//------------------------------------------------------------------------------

type backendMessageCode byte

const (
	_AuthenticationRequest backendMessageCode = 'R'
	_BackendKeyData        backendMessageCode = 'K'
	_BindComplete          backendMessageCode = '2'
	_CloseComplete         backendMessageCode = '3'
	_CommandComplete       backendMessageCode = 'C'
	_CopyData_BE           backendMessageCode = 'd'
	_CopyDone_BE           backendMessageCode = 'c'
	_CopyInResponse        backendMessageCode = 'G'
	_CopyOutResponse       backendMessageCode = 'H'
	_DataRow               backendMessageCode = 'D'
	_EmptyQueryResponse    backendMessageCode = 'I'
	_ErrorResponse         backendMessageCode = 'E'
	_FunctionCallResponse  backendMessageCode = 'V'
	_NoData                backendMessageCode = 'n'
	_NoticeResponse        backendMessageCode = 'N'
	_NotificationResponse  backendMessageCode = 'A'
	_ParameterDescription  backendMessageCode = 't'
	_ParameterStatus       backendMessageCode = 'S'
	_ParseComplete         backendMessageCode = '1'
	_PortalSuspended       backendMessageCode = 's'
	_ReadyForQuery         backendMessageCode = 'Z'
	_RowDescription        backendMessageCode = 'T'
)

var backendMsgCode2String map[backendMessageCode]string

func (x backendMessageCode) String() string {
	s, ok := backendMsgCode2String[x]
	if !ok {
		return fmt.Sprintf("unknown backendMessageCode: %02x", x)
	}

	return s
}

//------------------------------------------------------------------------------

type frontendMessageCode byte

const (
	_Bind            frontendMessageCode = 'B'
	_Close           frontendMessageCode = 'C'
	_CopyData_FE     frontendMessageCode = 'd'
	_CopyDone_FE     frontendMessageCode = 'c'
	_CopyFail        frontendMessageCode = 'f'
	_Describe        frontendMessageCode = 'D'
	_Execute         frontendMessageCode = 'E'
	_Flush           frontendMessageCode = 'H'
	_FunctionCall    frontendMessageCode = 'F'
	_Parse           frontendMessageCode = 'P'
	_PasswordMessage frontendMessageCode = 'p'
	_Query           frontendMessageCode = 'Q'
	_SSLRequest      frontendMessageCode = '8'
	_Sync            frontendMessageCode = 'S'
	_Terminate       frontendMessageCode = 'X'
)

var frontendMsgCode2String map[frontendMessageCode]string

func (x frontendMessageCode) String() string {
	s, ok := frontendMsgCode2String[x]
	if !ok {
		return "unkown frontendMessageCode"
	}

	return s
}

//------------------------------------------------------------------------------

type authenticationType int32

const (
	_AuthenticationOk                authenticationType = 0
	_AuthenticationKerberosV5        authenticationType = 2
	_AuthenticationCleartextPassword authenticationType = 3
	_AuthenticationMD5Password       authenticationType = 5
	_AuthenticationSCMCredential     authenticationType = 6
	_AuthenticationGSS               authenticationType = 7
	_AuthenticationGSSContinue       authenticationType = 8
	_AuthenticationSSPI              authenticationType = 9
)

var authType2String map[authenticationType]string

func (x authenticationType) String() string {
	s, ok := authType2String[x]
	if !ok {
		return "unkown authenticationType"
	}

	return s
}

//------------------------------------------------------------------------------

func init() {

	backendMsgCode2String = make(map[backendMessageCode]string)

	backendMsgCode2String[_AuthenticationRequest] = "AuthenticationRequest"
	backendMsgCode2String[_BackendKeyData] = "BackendKeyData"
	backendMsgCode2String[_BindComplete] = "BindComplete"
	backendMsgCode2String[_CloseComplete] = "CloseComplete"
	backendMsgCode2String[_CommandComplete] = "CommandComplete"
	backendMsgCode2String[_CopyData_BE] = "CopyData"
	backendMsgCode2String[_CopyDone_BE] = "CopyDone"
	backendMsgCode2String[_CopyInResponse] = "CopyInResponse"
	backendMsgCode2String[_CopyOutResponse] = "CopyOutResponse"
	backendMsgCode2String[_DataRow] = "DataRow"
	backendMsgCode2String[_EmptyQueryResponse] = "EmptyQueryResponse"
	backendMsgCode2String[_ErrorResponse] = "ErrorResponse"
	backendMsgCode2String[_FunctionCallResponse] = "FunctionCallResponse"
	backendMsgCode2String[_NoData] = "NoData"
	backendMsgCode2String[_NoticeResponse] = "NoticeResponse"
	backendMsgCode2String[_NotificationResponse] = "NotificationResponse"
	backendMsgCode2String[_ParameterDescription] = "ParameterDescription"
	backendMsgCode2String[_ParameterStatus] = "ParameterStatus"
	backendMsgCode2String[_ParseComplete] = "ParseComplete"
	backendMsgCode2String[_PortalSuspended] = "PortalSuspended"
	backendMsgCode2String[_ReadyForQuery] = "ReadyForQuery"
	backendMsgCode2String[_RowDescription] = "RowDescription"

	//--------

	frontendMsgCode2String = make(map[frontendMessageCode]string)

	frontendMsgCode2String[_Bind] = "Bind"
	frontendMsgCode2String[_Close] = "Close"
	frontendMsgCode2String[_CopyData_FE] = "CopyData"
	frontendMsgCode2String[_CopyDone_FE] = "CopyDone"
	frontendMsgCode2String[_CopyFail] = "CopyFail"
	frontendMsgCode2String[_Describe] = "Describe"
	frontendMsgCode2String[_Execute] = "Execute"
	frontendMsgCode2String[_Flush] = "Flush"
	frontendMsgCode2String[_FunctionCall] = "FunctionCall"
	frontendMsgCode2String[_Parse] = "Parse"
	frontendMsgCode2String[_PasswordMessage] = "PasswordMessage"
	frontendMsgCode2String[_Query] = "Query"
	frontendMsgCode2String[_SSLRequest] = "SSLRequest"
	frontendMsgCode2String[_Sync] = "Sync"
	frontendMsgCode2String[_Terminate] = "Terminate"

	//--------

	authType2String = make(map[authenticationType]string)

	authType2String[_AuthenticationOk] = "AuthenticationOk"
	authType2String[_AuthenticationKerberosV5] = "AuthenticationKerberosV5"
	authType2String[_AuthenticationCleartextPassword] = "AuthenticationCleartextPassword"
	authType2String[_AuthenticationMD5Password] = "AuthenticationMD5Password"
	authType2String[_AuthenticationSCMCredential] = "AuthenticationSCMCredential"
	authType2String[_AuthenticationGSS] = "AuthenticationGSS"
	authType2String[_AuthenticationGSSContinue] = "AuthenticationGSSContinue"
	authType2String[_AuthenticationSSPI] = "AuthenticationSSPI"
}
<|endoftext|>


<commit_before>package spawn

/*
Package spawn implements methods and interfaces used in downloading and spawning the underlying thrust core binary.
*/
import (
	"archive/zip"
	"fmt"
	"io"
	"log"
	"net/http"
	"os"
	"os/exec"
	"path/filepath"
	"runtime"
	"strings"
	"time"

	. "github.com/miketheprogrammer/go-thrust/common"
)

/*
The SpawnThrustCore method is a bootstrap and run method.
It will try to detect an installation of thrust, if it cannot find it
it will download the version of Thrust detailed in the "common" package.
Once downloaded, it will launch a process.
Go-Thrust and all *-Thrust packages communicate with Thrust Core via Stdin/Stdout.
using -log=debug as a command switch will give you the most information about what is going on. -log=info will give you notices that stuff is happening.
Any log level higher than that will output nothing.
*/

func SpawnThrustCore(dir string) (io.ReadCloser, io.WriteCloser) {
	//  if
	var thrustExecPath, thrustPath string
	thrustExecPath = GetExecutablePath(dir)
	thrustPath = GetThrustDirectory(dir)
	if len(thrustExecPath) > 0 {
		if _, err := os.Stat(thrustExecPath); os.IsNotExist(err) {
			Log.Info("Could not find executable:", thrustExecPath)
			Log.Info("Attempting to Download and Install the Thrust Core Executable")

			downloadFromUrl("https://github.com/breach/thrust/releases/download/v$V/thrust-v$V-darwin-x64.zip", THRUST_VERSION)
			unzip(strings.Replace("/tmp/$V", "$V", THRUST_VERSION, 1), thrustPath)

		}

		Log.Info("Attempting to start Thrust Core")
		Log.Debug("CMD:", thrustExecPath)
		cmd := exec.Command(thrustExecPath)
		cmdIn, e1 := cmd.StdinPipe()
		cmdOut, e2 := cmd.StdoutPipe()

		if e1 != nil {
			fmt.Println(e1)
			os.Exit(2)
		}

		if e2 != nil {
			fmt.Println(e2)
			os.Exit(2)
		}

		if Log.LogDebug() {
			cmd.Stderr = os.Stdout
		}

		cmd.Start()

		Log.Info("Thrust Core started.")
		return cmdOut, cmdIn
	} else {
		fmt.Println("===============WARNING================")
		fmt.Println("Current operating system not supported", runtime.GOOS)
		fmt.Println("===============END====================")
	}
	return nil, nil
}

func downloadFromUrl(url, version string) {
	url = strings.Replace(url, "$V", version, 2)
	fileName := strings.Replace("/tmp/$V", "$V", version, 1)
	if Log.LogInfo() {
		fmt.Println("Downloading", url, "to", fileName)
	}

	quit := make(chan int, 1)

	go func() {
		for {
			select {
			case <-quit:
				fmt.Print("\n")
				return
			default:
				if Log.LogInfo() {
					fmt.Print(".")
				}
			}
			time.Sleep(time.Second)
		}
	}()

	// TODO: check file existence first with io.IsExist
	output, err := os.Create(fileName)
	if err != nil {
		fmt.Println("Error while creating", fileName, "-", err)
		return
	}
	defer output.Close()

	response, err := http.Get(url)
	if err != nil {
		fmt.Println("Error while downloading", url, "-", err)
		return
	}
	defer response.Body.Close()

	n, err := io.Copy(output, response.Body)
	if err != nil {
		fmt.Println("Error while downloading", url, "-", err)
		return
	}
	quit <- 1

	fmt.Println(n, "bytes downloaded.")
}
func unzip(src, dest string) error {
	r, err := zip.OpenReader(src)
	if err != nil {
		return err
	}
	defer r.Close()
	if Log.LogInfo() {
		fmt.Println("Unzipping", src, "to", dest)
	}

	quit := make(chan int, 1)

	go func() {
		for {
			select {
			case <-quit:
				fmt.Print("\n")
				return
			default:
				if Log.LogInfo() {
					fmt.Print(".")
				}
			}
			time.Sleep(time.Second)
		}
	}()
	for _, f := range r.File {
		rc, err := f.Open()
		if err != nil {
			return err
		}
		defer rc.Close()

		fpath := filepath.Join(dest, f.Name)
		if f.FileInfo().IsDir() {
			os.MkdirAll(fpath, f.Mode())
		} else {
			var fdir string
			if lastIndex := strings.LastIndex(fpath, string(os.PathSeparator)); lastIndex > -1 {
				fdir = fpath[:lastIndex]
			}

			err = os.MkdirAll(fdir, f.Mode())
			if err != nil {
				log.Fatal(err)
				return err
			}
			f, err := os.OpenFile(
				fpath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, f.Mode())
			if err != nil {
				return err
			}
			defer f.Close()

			_, err = io.Copy(f, rc)
			if err != nil {
				return err
			}
		}
	}
	quit <- 1
	return nil
}
<commit_msg>Fix linux build pt2, download url<commit_after>package spawn

/*
Package spawn implements methods and interfaces used in downloading and spawning the underlying thrust core binary.
*/
import (
	"archive/zip"
	"fmt"
	"io"
	"log"
	"net/http"
	"os"
	"os/exec"
	"path/filepath"
	"runtime"
	"strings"
	"time"

	. "github.com/miketheprogrammer/go-thrust/common"
)

/*
The SpawnThrustCore method is a bootstrap and run method.
It will try to detect an installation of thrust, if it cannot find it
it will download the version of Thrust detailed in the "common" package.
Once downloaded, it will launch a process.
Go-Thrust and all *-Thrust packages communicate with Thrust Core via Stdin/Stdout.
using -log=debug as a command switch will give you the most information about what is going on. -log=info will give you notices that stuff is happening.
Any log level higher than that will output nothing.
*/

func SpawnThrustCore(dir string) (io.ReadCloser, io.WriteCloser) {
	//  if
	var thrustExecPath, thrustPath string
	thrustExecPath = GetExecutablePath(dir)
	thrustPath = GetThrustDirectory(dir)
	if len(thrustExecPath) > 0 {
		if _, err := os.Stat(thrustExecPath); os.IsNotExist(err) {
			Log.Info("Could not find executable:", thrustExecPath)
			Log.Info("Attempting to Download and Install the Thrust Core Executable")

			downloadFromUrl(GetDownloadUrl(), THRUST_VERSION)
			unzip(strings.Replace("/tmp/$V", "$V", THRUST_VERSION, 1), thrustPath)

		}

		Log.Info("Attempting to start Thrust Core")
		Log.Debug("CMD:", thrustExecPath)
		cmd := exec.Command(thrustExecPath)
		cmdIn, e1 := cmd.StdinPipe()
		cmdOut, e2 := cmd.StdoutPipe()

		if e1 != nil {
			fmt.Println(e1)
			os.Exit(2)
		}

		if e2 != nil {
			fmt.Println(e2)
			os.Exit(2)
		}

		if Log.LogDebug() {
			cmd.Stderr = os.Stdout
		}

		cmd.Start()

		Log.Info("Thrust Core started.")
		return cmdOut, cmdIn
	} else {
		fmt.Println("===============WARNING================")
		fmt.Println("Current operating system not supported", runtime.GOOS)
		fmt.Println("===============END====================")
	}
	return nil, nil
}

func downloadFromUrl(url, version string) {
	url = strings.Replace(url, "$V", version, 2)
	fileName := strings.Replace("/tmp/$V", "$V", version, 1)
	if Log.LogInfo() {
		fmt.Println("Downloading", url, "to", fileName)
	}

	quit := make(chan int, 1)

	go func() {
		for {
			select {
			case <-quit:
				fmt.Print("\n")
				return
			default:
				if Log.LogInfo() {
					fmt.Print(".")
				}
			}
			time.Sleep(time.Second)
		}
	}()

	// TODO: check file existence first with io.IsExist
	output, err := os.Create(fileName)
	if err != nil {
		fmt.Println("Error while creating", fileName, "-", err)
		return
	}
	defer output.Close()

	response, err := http.Get(url)
	if err != nil {
		fmt.Println("Error while downloading", url, "-", err)
		return
	}
	defer response.Body.Close()

	n, err := io.Copy(output, response.Body)
	if err != nil {
		fmt.Println("Error while downloading", url, "-", err)
		return
	}
	quit <- 1

	fmt.Println(n, "bytes downloaded.")
}
func unzip(src, dest string) error {
	r, err := zip.OpenReader(src)
	if err != nil {
		return err
	}
	defer r.Close()
	if Log.LogInfo() {
		fmt.Println("Unzipping", src, "to", dest)
	}

	quit := make(chan int, 1)

	go func() {
		for {
			select {
			case <-quit:
				fmt.Print("\n")
				return
			default:
				if Log.LogInfo() {
					fmt.Print(".")
				}
			}
			time.Sleep(time.Second)
		}
	}()
	for _, f := range r.File {
		rc, err := f.Open()
		if err != nil {
			return err
		}
		defer rc.Close()

		fpath := filepath.Join(dest, f.Name)
		if f.FileInfo().IsDir() {
			os.MkdirAll(fpath, f.Mode())
		} else {
			var fdir string
			if lastIndex := strings.LastIndex(fpath, string(os.PathSeparator)); lastIndex > -1 {
				fdir = fpath[:lastIndex]
			}

			err = os.MkdirAll(fdir, f.Mode())
			if err != nil {
				log.Fatal(err)
				return err
			}
			f, err := os.OpenFile(
				fpath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, f.Mode())
			if err != nil {
				return err
			}
			defer f.Close()

			_, err = io.Copy(f, rc)
			if err != nil {
				return err
			}
		}
	}
	quit <- 1
	return nil
}
<|endoftext|>


<commit_before>package MCP23S17

import (
	"github.com/luismesas/go-rpi/spi"
)

const (
	MCP23S17_MODE = 0
	MCP23S17_BPW = 8
	MCP23S17_SPEED = 10000000
)

//	Microchip's MCP23S17: A 16-Bit I/O Expander with Serial Interface.
type MCP23S17 struct{
	Device *spi.SPIDevice
	HardwareAddress byte

	// Controls the direction of the data I/O.
	IODIRa *MCP23S17Register
	IODIRb *MCP23S17Register

	// This register allows the user to configure the polarity on the corresponding GPIO port bits.
	IPOLa *MCP23S17Register
	IPOLb *MCP23S17Register

	// The GPINTEN register controls the interrupt-onchange feature for each pin.
	GPINTENa *MCP23S17Register
	GPINTENb *MCP23S17Register

	// The default comparison value is configured in the DEFVAL register.
	DEFVALa *MCP23S17Register
	DEFVALb *MCP23S17Register

	// The INTCON register controls how the associated pin value is compared for the interrupt-on-change feature.
	INTCONa *MCP23S17Register
	INTCONb *MCP23S17Register

	// The IOCON register contains several bits for configuring the device.
	IOCON *MCP23S17Register

	// The GPPU register controls the pull-up esistors for the port pins.
	GPPUa *MCP23S17Register
	GPPUb *MCP23S17Register

	// The INTF register reflects the interrupt condition on the port pins of any pin that is enabled for interrupts via the GPINTEN register.
	INTFa *MCP23S17Register
	INTFb *MCP23S17Register

	// The INTCAP register captures the GPIO port value at the time the interrupt occurred.
	INTCAPa *MCP23S17Register
	INTCAPb *MCP23S17Register

	// The GPIO register reflects the value on the port.
	GPIOa *MCP23S17Register
	GPIOb *MCP23S17Register

	// The OLAT register provides access to the output latches.
	OLATa *MCP23S17Register
	OLATb *MCP23S17Register
}

func NewMCP23S17(hardwareAddress uint8, bus int, chip_select int) *MCP23S17{
	mcp := new(MCP23S17)
	mcp.Device = spi.NewSPIDevice(bus, chip_select)
	mcp.HardwareAddress = hardwareAddress

	mcp.IODIRa = NewMCP23S17Register(IODIRA, mcp)
	mcp.IODIRb = NewMCP23S17Register(IODIRB, mcp)
	mcp.IPOLa = NewMCP23S17Register(IPOLA, mcp)
	mcp.IPOLb = NewMCP23S17Register(IPOLB, mcp)
	mcp.GPINTENa = NewMCP23S17Register(GPINTENA, mcp)
	mcp.GPINTENb = NewMCP23S17Register(GPINTENB, mcp)
	mcp.DEFVALa = NewMCP23S17Register(DEFVALA, mcp)
	mcp.DEFVALb = NewMCP23S17Register(DEFVALB, mcp)
	mcp.INTCONa = NewMCP23S17Register(INTCONA, mcp)
	mcp.INTCONb = NewMCP23S17Register(INTCONB, mcp)
	mcp.IOCON = NewMCP23S17Register(IOCON, mcp)
	mcp.GPPUa = NewMCP23S17Register(GPPUA, mcp)
	mcp.GPPUb = NewMCP23S17Register(GPPUB, mcp)
	mcp.INTFa = NewMCP23S17Register(INTFA, mcp)
	mcp.INTFb = NewMCP23S17Register(INTFB, mcp)
	mcp.INTCAPa = NewMCP23S17Register(INTCAPA, mcp)
	mcp.INTCAPb = NewMCP23S17Register(INTCAPB, mcp)
	mcp.GPIOa = NewMCP23S17Register(GPIOA, mcp)
	mcp.GPIOb = NewMCP23S17Register(GPIOB, mcp)
	mcp.OLATa = NewMCP23S17Register(OLATA, mcp)
	mcp.OLATb = NewMCP23S17Register(OLATB, mcp)

	return mcp
}

func (mcp *MCP23S17) Open() error{

	err := mcp.Device.Open()
	if err != nil {
		return err
	}

	err = mcp.Device.SetMode(MCP23S17_MODE)
	if err != nil {
		return err
	}

	err = mcp.Device.SetBitsPerWord(MCP23S17_BPW)
	if err != nil {
		return err
	}

	err = mcp.Device.SetSpeed(MCP23S17_SPEED)
	if err != nil {
		return err
	}

	return nil
}

func (mcp *MCP23S17) Close() error{
	return mcp.Device.Close()
}

// Returns an SPI control byte.
// The MCP23S17 is a slave SPI device. The slave address contains
// four fixed bits and three user-defined hardware address bits
// (if enabled via IOCON.HAEN) (pins A2, A1 and A0) with the
// read/write bit filling out the control byte::

// 	+--------------------+
// 	|0|1|0|0|A2|A1|A0|R/W|
// 	+--------------------+
// 	 7 6 5 4 3  2  1   0

// :param read_write_cmd: Read or write command.
// :type read_write_cmd: int
func (mcp *MCP23S17) getSPIControlByte(read_write_cmd uint8) byte {
	board_addr_pattern := (mcp.HardwareAddress << 1) & 0xE
	rw_cmd_pattern := read_write_cmd & 0x01  // make sure it's just 1 bit long
	return 0x40 | board_addr_pattern | rw_cmd_pattern
}

// Returns the value of the address specified.
func (mcp *MCP23S17) Read(address byte) byte{
	ctrl_byte := mcp.getSPIControlByte(READ_CMD)
	data, err := mcp.Device.Send([3]byte{ctrl_byte, address, 0})
	if err != nil {
		panic("Error reading from MCP23S17: %s\n", err)
		return 0x00
	}
	if len(data) == 0 {
		return 0x00
	} else {
		return data[2]
	}
}

// Writes data to the address specified.
func (mcp *MCP23S17) Write(data byte, address byte){
	ctrl_byte := mcp.getSPIControlByte(WRITE_CMD)
	_, err := mcp.Device.Send([3]byte{ctrl_byte, address, data})
	if err != nil {
		panic("Error writing on MCP23S17: %s\n", err)
	}
}

// Returns the bit specified from the address.
func (mcp *MCP23S17) ReadBit(bit_num uint, address byte) byte{
	value := mcp.Read(address)
	return (value >> bit_num) & 1
}

// Writes the value given to the bit in the address specified.
func (mcp *MCP23S17) WriteBit(data byte, bit_num uint, address byte){
	value := mcp.Read(address)
	if data > 0 {
		value = value | (1 << bit_num) //set
	} else {
		value = value & ( 0xff ^ (1 << bit_num)) //clear
	}
	mcp.Write(value, address)
}

// Clears the interrupt flags by reading the capture register.
func (mcp *MCP23S17) ClearInterrupts(port int){
	var address byte
	address = INTCAPA
	if port == GPIOA {
		address = INTCAPB
	}
	mcp.Read(address)
}
<commit_msg>panics are now correct<commit_after>package MCP23S17

import (
	"fmt"
	"github.com/luismesas/go-rpi/spi"
)

const (
	MCP23S17_MODE = 0
	MCP23S17_BPW = 8
	MCP23S17_SPEED = 10000000
)

//	Microchip's MCP23S17: A 16-Bit I/O Expander with Serial Interface.
type MCP23S17 struct{
	Device *spi.SPIDevice
	HardwareAddress byte

	// Controls the direction of the data I/O.
	IODIRa *MCP23S17Register
	IODIRb *MCP23S17Register

	// This register allows the user to configure the polarity on the corresponding GPIO port bits.
	IPOLa *MCP23S17Register
	IPOLb *MCP23S17Register

	// The GPINTEN register controls the interrupt-onchange feature for each pin.
	GPINTENa *MCP23S17Register
	GPINTENb *MCP23S17Register

	// The default comparison value is configured in the DEFVAL register.
	DEFVALa *MCP23S17Register
	DEFVALb *MCP23S17Register

	// The INTCON register controls how the associated pin value is compared for the interrupt-on-change feature.
	INTCONa *MCP23S17Register
	INTCONb *MCP23S17Register

	// The IOCON register contains several bits for configuring the device.
	IOCON *MCP23S17Register

	// The GPPU register controls the pull-up esistors for the port pins.
	GPPUa *MCP23S17Register
	GPPUb *MCP23S17Register

	// The INTF register reflects the interrupt condition on the port pins of any pin that is enabled for interrupts via the GPINTEN register.
	INTFa *MCP23S17Register
	INTFb *MCP23S17Register

	// The INTCAP register captures the GPIO port value at the time the interrupt occurred.
	INTCAPa *MCP23S17Register
	INTCAPb *MCP23S17Register

	// The GPIO register reflects the value on the port.
	GPIOa *MCP23S17Register
	GPIOb *MCP23S17Register

	// The OLAT register provides access to the output latches.
	OLATa *MCP23S17Register
	OLATb *MCP23S17Register
}

func NewMCP23S17(hardwareAddress uint8, bus int, chip_select int) *MCP23S17{
	mcp := new(MCP23S17)
	mcp.Device = spi.NewSPIDevice(bus, chip_select)
	mcp.HardwareAddress = hardwareAddress

	mcp.IODIRa = NewMCP23S17Register(IODIRA, mcp)
	mcp.IODIRb = NewMCP23S17Register(IODIRB, mcp)
	mcp.IPOLa = NewMCP23S17Register(IPOLA, mcp)
	mcp.IPOLb = NewMCP23S17Register(IPOLB, mcp)
	mcp.GPINTENa = NewMCP23S17Register(GPINTENA, mcp)
	mcp.GPINTENb = NewMCP23S17Register(GPINTENB, mcp)
	mcp.DEFVALa = NewMCP23S17Register(DEFVALA, mcp)
	mcp.DEFVALb = NewMCP23S17Register(DEFVALB, mcp)
	mcp.INTCONa = NewMCP23S17Register(INTCONA, mcp)
	mcp.INTCONb = NewMCP23S17Register(INTCONB, mcp)
	mcp.IOCON = NewMCP23S17Register(IOCON, mcp)
	mcp.GPPUa = NewMCP23S17Register(GPPUA, mcp)
	mcp.GPPUb = NewMCP23S17Register(GPPUB, mcp)
	mcp.INTFa = NewMCP23S17Register(INTFA, mcp)
	mcp.INTFb = NewMCP23S17Register(INTFB, mcp)
	mcp.INTCAPa = NewMCP23S17Register(INTCAPA, mcp)
	mcp.INTCAPb = NewMCP23S17Register(INTCAPB, mcp)
	mcp.GPIOa = NewMCP23S17Register(GPIOA, mcp)
	mcp.GPIOb = NewMCP23S17Register(GPIOB, mcp)
	mcp.OLATa = NewMCP23S17Register(OLATA, mcp)
	mcp.OLATb = NewMCP23S17Register(OLATB, mcp)

	return mcp
}

func (mcp *MCP23S17) Open() error{

	err := mcp.Device.Open()
	if err != nil {
		return err
	}

	err = mcp.Device.SetMode(MCP23S17_MODE)
	if err != nil {
		return err
	}

	err = mcp.Device.SetBitsPerWord(MCP23S17_BPW)
	if err != nil {
		return err
	}

	err = mcp.Device.SetSpeed(MCP23S17_SPEED)
	if err != nil {
		return err
	}

	return nil
}

func (mcp *MCP23S17) Close() error{
	return mcp.Device.Close()
}

// Returns an SPI control byte.
// The MCP23S17 is a slave SPI device. The slave address contains
// four fixed bits and three user-defined hardware address bits
// (if enabled via IOCON.HAEN) (pins A2, A1 and A0) with the
// read/write bit filling out the control byte::

// 	+--------------------+
// 	|0|1|0|0|A2|A1|A0|R/W|
// 	+--------------------+
// 	 7 6 5 4 3  2  1   0

// :param read_write_cmd: Read or write command.
// :type read_write_cmd: int
func (mcp *MCP23S17) getSPIControlByte(read_write_cmd uint8) byte {
	board_addr_pattern := (mcp.HardwareAddress << 1) & 0xE
	rw_cmd_pattern := read_write_cmd & 0x01  // make sure it's just 1 bit long
	return 0x40 | board_addr_pattern | rw_cmd_pattern
}

// Returns the value of the address specified.
func (mcp *MCP23S17) Read(address byte) byte{
	ctrl_byte := mcp.getSPIControlByte(READ_CMD)
	data, err := mcp.Device.Send([3]byte{ctrl_byte, address, 0})
	if err != nil {
		panic(fmt.Sprintf("Error reading from MCP23S17: %s\n", err))
		return 0x00
	}
	if len(data) == 0 {
		return 0x00
	} else {
		return data[2]
	}
}

// Writes data to the address specified.
func (mcp *MCP23S17) Write(data byte, address byte){
	ctrl_byte := mcp.getSPIControlByte(WRITE_CMD)
	_, err := mcp.Device.Send([3]byte{ctrl_byte, address, data})
	if err != nil {
		panic(fmt.Sprintf("Error writing on MCP23S17: %s\n", err))
	}
}

// Returns the bit specified from the address.
func (mcp *MCP23S17) ReadBit(bit_num uint, address byte) byte{
	value := mcp.Read(address)
	return (value >> bit_num) & 1
}

// Writes the value given to the bit in the address specified.
func (mcp *MCP23S17) WriteBit(data byte, bit_num uint, address byte){
	value := mcp.Read(address)
	if data > 0 {
		value = value | (1 << bit_num) //set
	} else {
		value = value & ( 0xff ^ (1 << bit_num)) //clear
	}
	mcp.Write(value, address)
}

// Clears the interrupt flags by reading the capture register.
func (mcp *MCP23S17) ClearInterrupts(port int){
	var address byte
	address = INTCAPA
	if port == GPIOA {
		address = INTCAPB
	}
	mcp.Read(address)
}
<|endoftext|>