<commit_before>package epgc

import (
	"database/sql"
	"log"
	"time"

	"github.com/lib/pq"
)

// Training - struct for training
type Training struct {
	ID        int64     `sql:"id" json:"id" `
	StartDate time.Time `sql:"start_date" json:"start-date"`
	EndDate   time.Time `sql:"end_date" json:"end-date"`
	StartStr  string    `sql:"-" json:"start-str"`
	EndStr    string    `sql:"-" json:"end-str"`
	Note      string    `sql:"note, null" json:"note"`
	CreatedAt time.Time `sql:"created_at" json:"created_at"`
	UpdatedAt time.Time `sql:"updated_at" json:"updated_at"`
}

func scanTraining(row *sql.Row) (Training, error) {
	var (
		sID        sql.NullInt64
		sStartDate pq.NullTime
		sEndDate   pq.NullTime
		sNote      sql.NullString
		training   Training
	)
	err := row.Scan(&sID, &sStartDate, &sEndDate, &sNote)
	if err != nil {
		log.Println("scanTraining row.Scan ", err)
		return training, err
	}
	training.ID = n2i(sID)
	training.StartDate = n2d(sStartDate)
	training.EndDate = n2d(sEndDate)
	training.Note = n2s(sNote)
	return training, nil
}

func scanTrainings(rows *sql.Rows, opt string) ([]Training, error) {
	var trainings []Training
	for rows.Next() {
		var (
			sID        sql.NullInt64
			sStartDate pq.NullTime
			sEndDate   pq.NullTime
			sNote      sql.NullString
			training   Training
		)
		switch opt {
		case "list":
			err := rows.Scan(&sID, &sStartDate, &sEndDate, &sNote)
			if err != nil {
				log.Println("scanTrainings rows.Scan list ", err)
				return trainings, err
			}
		}
		training.ID = n2i(sID)
		training.StartDate = n2d(sStartDate)
		training.EndDate = n2d(sEndDate)
		training.Note = n2s(sNote)
		trainings = append(trainings, training)
	}
	err := rows.Err()
	if err != nil {
		log.Println("scanTrainings rows.Err ", err)
	}
	return trainings, err
}

// GetTraining - get training by id
func (e *Edb) GetTraining(id int64) (Training, error) {
	if id == 0 {
		return Training{}, nil
	}
	stmt, err := e.db.Prepare(`SELECT
		id,
		start_date
		end_date,
		note
	FROM
		trainings
	ORDER BY
		start_date
	WHERE id = $1`)
	if err != nil {
		log.Println("GetTraining e.db.Prepare ", err)
		return Training{}, err
	}
	row := stmt.QueryRow(id)
	training, err := scanTraining(row)
	return training, err
}

// GetTrainingList - get all training for list
func (e *Edb) GetTrainingList() ([]Training, error) {
	rows, err := e.db.Query(`SELECT
		id,
		start_date
		end_date,
		note
	FROM
		trainings
	ORDER BY
		start_date`)
	if err != nil {
		log.Println("GetTrainingList e.db.Query ", err)
		return []Training{}, err
	}
	trainings, err := scanTrainings(rows, "list")
	if err != nil {
		log.Println("GetTrainingList scanTrainings ", err)
		return []Training{}, err
	}
	for i := range trainings {
		trainings[i].StartStr = setStrMonth(trainings[i].StartDate)
		trainings[i].EndStr = setStrMonth(trainings[i].EndDate)
	}
	return trainings, err
}

// CreateTraining - create new training
func (e *Edb) CreateTraining(training Training) (int64, error) {
	stmt, err := e.db.Prepare(`INSERT INTO trainings(start_date, end_date, note, created_at) VALUES($1, $2, $3, now()) RETURNING id`)
	if err != nil {
		log.Println("CreateTraining e.db.Prepare ", err)
		return 0, err
	}
	err = stmt.QueryRow(d2n(training.StartDate), d2n(training.EndDate), s2n(training.Note)).Scan(&training.ID)
	return training.ID, err
}

// UpdateTraining - save changes to training
func (e *Edb) UpdateTraining(training Training) error {
	stmt, err := e.db.Prepare(`UPDATE trainings SET start_date = $2, end_date = $3, note = $4, updated_at = now() WHERE id = $1`)
	if err != nil {
		log.Println("UpdateTraining e.db.Prepare ", err)
		return err
	}
	_, err = stmt.Exec(training.ID, d2n(training.StartDate), d2n(training.EndDate), s2n(training.Note))
	return err
}

// DeleteTraining - delete training by id
func (e *Edb) DeleteTraining(id int64) error {
	if id == 0 {
		return nil
	}
	_, err := e.db.Exec(`DELETE * FROM trainings WHERE id = $1`, id)
	if err != nil {
		log.Println("DeleteTraining ", err)
	}
	return err
}

func (e *Edb) trainingCreateTable() error {
	str := `CREATE TABLE IF NOT EXISTS trainings (id bigserial primary key, start_date date, end_date date, note text, created_at TIMESTAMP without time zone, updated_at TIMESTAMP without time zone)`
	_, err := e.db.Exec(str)
	if err != nil {
		log.Println("trainingCreateTable ", err)
	}
	return err
}
<commit_msg>fix sql<commit_after>package epgc

import (
	"database/sql"
	"log"
	"time"

	"github.com/lib/pq"
)

// Training - struct for training
type Training struct {
	ID        int64     `sql:"id" json:"id" `
	StartDate time.Time `sql:"start_date" json:"start-date"`
	EndDate   time.Time `sql:"end_date" json:"end-date"`
	StartStr  string    `sql:"-" json:"start-str"`
	EndStr    string    `sql:"-" json:"end-str"`
	Note      string    `sql:"note, null" json:"note"`
	CreatedAt time.Time `sql:"created_at" json:"created_at"`
	UpdatedAt time.Time `sql:"updated_at" json:"updated_at"`
}

func scanTraining(row *sql.Row) (Training, error) {
	var (
		sID        sql.NullInt64
		sStartDate pq.NullTime
		sEndDate   pq.NullTime
		sNote      sql.NullString
		training   Training
	)
	err := row.Scan(&sID, &sStartDate, &sEndDate, &sNote)
	if err != nil {
		log.Println("scanTraining row.Scan ", err)
		return training, err
	}
	training.ID = n2i(sID)
	training.StartDate = n2d(sStartDate)
	training.EndDate = n2d(sEndDate)
	training.Note = n2s(sNote)
	return training, nil
}

func scanTrainings(rows *sql.Rows, opt string) ([]Training, error) {
	var trainings []Training
	for rows.Next() {
		var (
			sID        sql.NullInt64
			sStartDate pq.NullTime
			sEndDate   pq.NullTime
			sNote      sql.NullString
			training   Training
		)
		switch opt {
		case "list":
			err := rows.Scan(&sID, &sStartDate, &sEndDate, &sNote)
			if err != nil {
				log.Println("scanTrainings rows.Scan list ", err)
				return trainings, err
			}
		}
		training.ID = n2i(sID)
		training.StartDate = n2d(sStartDate)
		training.EndDate = n2d(sEndDate)
		training.Note = n2s(sNote)
		trainings = append(trainings, training)
	}
	err := rows.Err()
	if err != nil {
		log.Println("scanTrainings rows.Err ", err)
	}
	return trainings, err
}

// GetTraining - get training by id
func (e *Edb) GetTraining(id int64) (Training, error) {
	if id == 0 {
		return Training{}, nil
	}
	stmt, err := e.db.Prepare(`SELECT
		id,
		start_date,
		end_date,
		note
	FROM
		trainings
	WHERE id = $1
	ORDER BY
		start_date`)
	if err != nil {
		log.Println("GetTraining e.db.Prepare ", err)
		return Training{}, err
	}
	row := stmt.QueryRow(id)
	training, err := scanTraining(row)
	return training, err
}

// GetTrainingList - get all training for list
func (e *Edb) GetTrainingList() ([]Training, error) {
	rows, err := e.db.Query(`SELECT
		id,
		start_date,
		end_date,
		note
	FROM
		trainings
	ORDER BY
		start_date`)
	if err != nil {
		log.Println("GetTrainingList e.db.Query ", err)
		return []Training{}, err
	}
	trainings, err := scanTrainings(rows, "list")
	if err != nil {
		log.Println("GetTrainingList scanTrainings ", err)
		return []Training{}, err
	}
	for i := range trainings {
		trainings[i].StartStr = setStrMonth(trainings[i].StartDate)
		trainings[i].EndStr = setStrMonth(trainings[i].EndDate)
	}
	return trainings, err
}

// CreateTraining - create new training
func (e *Edb) CreateTraining(training Training) (int64, error) {
	stmt, err := e.db.Prepare(`INSERT INTO trainings(start_date, end_date, note, created_at) VALUES($1, $2, $3, now()) RETURNING id`)
	if err != nil {
		log.Println("CreateTraining e.db.Prepare ", err)
		return 0, err
	}
	err = stmt.QueryRow(d2n(training.StartDate), d2n(training.EndDate), s2n(training.Note)).Scan(&training.ID)
	return training.ID, err
}

// UpdateTraining - save changes to training
func (e *Edb) UpdateTraining(training Training) error {
	stmt, err := e.db.Prepare(`UPDATE trainings SET start_date = $2, end_date = $3, note = $4, updated_at = now() WHERE id = $1`)
	if err != nil {
		log.Println("UpdateTraining e.db.Prepare ", err)
		return err
	}
	_, err = stmt.Exec(training.ID, d2n(training.StartDate), d2n(training.EndDate), s2n(training.Note))
	return err
}

// DeleteTraining - delete training by id
func (e *Edb) DeleteTraining(id int64) error {
	if id == 0 {
		return nil
	}
	_, err := e.db.Exec(`DELETE * FROM trainings WHERE id = $1`, id)
	if err != nil {
		log.Println("DeleteTraining ", err)
	}
	return err
}

func (e *Edb) trainingCreateTable() error {
	str := `CREATE TABLE IF NOT EXISTS trainings (id bigserial primary key, start_date date, end_date date, note text, created_at TIMESTAMP without time zone, updated_at TIMESTAMP without time zone)`
	_, err := e.db.Exec(str)
	if err != nil {
		log.Println("trainingCreateTable ", err)
	}
	return err
}
<|endoftext|>


<commit_before>//
// daemon.go
//
package srnd
import (
  "log"
  "net"
  "net/textproto"
  "strconv"
  "strings"
  "os"
  "time"
)

type NNTPDaemon struct {
  instance_name string
  bind_addr string
  conf *SRNdConfig
  store ArticleStore
  database Database
  mod ModEngine
  expire ExpirationCore
  listener net.Listener
  debug bool
  sync_on_start bool
  // anon settings
  allow_anon bool
  allow_anon_attachments bool

  running bool
  // http frontend
  frontend Frontend

  // map of addr -> NNTPConnection
  feeds map[string]nntpConnection
  // for registering and deregistering outbound feeds
  register_outfeed chan nntpConnection
  deregister_outfeed chan nntpConnection
  // infeed for articles
  infeed chan NNTPMessage
  // channel to load messages to infeed given their message id
  infeed_load chan string
  // channel for broadcasting a message to all feeds given their newsgroup, message_id
  send_all_feeds chan ArticleEntry
  // channel for broadcasting an ARTICLE command to all feeds in reader mode
  ask_for_article chan ArticleEntry
}

func (self NNTPDaemon) End() {
  self.listener.Close()
}

func (self NNTPDaemon) persistFeed(conf FeedConfig, mode string) {
  for {
    if self.running {

      var conn net.Conn
      var err error
      proxy_type := strings.ToLower(conf.proxy_type)

      if proxy_type ==  "" || proxy_type == "none" {
        // connect out without proxy
        log.Println("dial out to ", conf.addr)
        conn, err = net.Dial("tcp", conf.addr)
        if err != nil {
          log.Println("cannot connect to outfeed", conf.addr, err)
					time.Sleep(time.Second * 5)
          continue
        }
      } else if proxy_type == "socks4a" {
        // connect via socks4a
        log.Println("dial out via proxy", conf.proxy_addr)
        conn, err = net.Dial("tcp", conf.proxy_addr)
        if err != nil {
          log.Println("cannot connect to proxy", conf.proxy_addr)
					time.Sleep(time.Second * 5)
          continue
        }
        // generate request
        idx := strings.LastIndex(conf.addr, ":")
        if idx == -1 {
          log.Fatal("invalid outfeed address")
        }
        var port uint64
        addr := conf.addr[:idx]
        port, err = strconv.ParseUint(conf.addr[idx+1:], 10, 16)
        if port >= 25536 {
          log.Fatal("bad proxy port" , port)
        }
        var proxy_port uint16
        proxy_port = uint16(port)
        proxy_ident := "srndv2"
        req_len := len(addr) + 1 + len(proxy_ident) + 1 + 8

        req := make([]byte, req_len)
        // pack request
        req[0] = '\x04'
        req[1] = '\x01'
        req[2] = byte(proxy_port & 0xff00 >> 8)
        req[3] = byte(proxy_port & 0x00ff)
        req[7] = '\x01'
        idx = 8

        proxy_ident_b := []byte(proxy_ident)
        addr_b := []byte(addr)

        var bi int
        for bi = range proxy_ident_b {
          req[idx] = proxy_ident_b[bi]
          idx += 1
        }
        idx += 1
        for bi = range addr_b {
          req[idx] = addr_b[bi]
          idx += 1
        }

        // send request
        conn.Write(req)
        resp := make([]byte, 8)

        // receive response
        conn.Read(resp)
        if resp[1] == '\x5a' {
          // success
          log.Println("connected to", conf.addr)
        } else {
          log.Println("failed to connect to", conf.addr)
					time.Sleep(time.Second * 5)
          continue
        }
      }
      nntp := createNNTPConnection()
      nntp.policy = conf.policy
      nntp.name = conf.addr
      c := textproto.NewConn(conn)
      stream, reader, err := nntp.outboundHandshake(c)
      if err == nil {
        self.register_outfeed <- nntp
        if self.sync_on_start {
          go func() {
            log.Println(nntp.name, "will do full sync")
            for _, article := range self.database.GetAllArticles() {
              if nntp.policy.AllowsNewsgroup(article.Newsgroup()) {
                nntp.check <- article.MessageID()
              }
            }

          }()
        }
        // don't use streaming if we have set mode reader
        ok, err := nntp.modeSwitch(mode, c)
        if ok {
          nntp.runConnection(self, false, stream, reader, c)
        } else {
          log.Println("failed to switch modes", err)
        }
        self.deregister_outfeed <- nntp

      } else {
        log.Println("error doing outbound hanshake", err)
      }
    }
  }
  time.Sleep(1 * time.Second)
}

// run daemon
func (self NNTPDaemon) Run() {

  self.bind_addr = self.conf.daemon["bind"]

  listener , err := net.Listen("tcp", self.bind_addr)
  if err != nil {
    log.Fatal("failed to bind to", self.bind_addr, err)
  }
  self.listener = listener
  log.Printf("SRNd NNTPD bound at %s", listener.Addr())

  self.register_outfeed = make(chan nntpConnection)
  self.deregister_outfeed = make(chan nntpConnection)
  self.infeed = make(chan NNTPMessage, 8)
  self.infeed_load = make(chan string)
  self.send_all_feeds = make(chan ArticleEntry, 64)
  self.feeds = make(map[string]nntpConnection)
  self.ask_for_article = make(chan ArticleEntry, 64)

  self.expire = createExpirationCore(self.database, self.store)
  self.sync_on_start = self.conf.daemon["sync_on_start"] == "1"
  self.debug = self.conf.daemon["log"] == "debug"
  self.instance_name = self.conf.daemon["instance_name"]
  self.allow_anon = self.conf.daemon["allow_anon"] == "1"
  self.allow_anon_attachments = self.conf.daemon["allow_anon_attachments"] == "1"

  if self.debug {
    log.Println("debug mode activated")
  }

  // do we enable the frontend?
  if self.conf.frontend["enable"] == "1" {
    log.Printf("frontend %s enabled", self.conf.frontend["name"])
    http_frontend := NewHTTPFrontend(&self, self.conf.frontend, self.conf.worker["url"])
    nntp_frontend := NewNNTPFrontend(&self, self.conf.frontend["nntp"])
    self.frontend = MuxFrontends(http_frontend, nntp_frontend)
    go self.frontend.Mainloop()
  }

  // set up admin user if it's specified in the config
  pubkey , ok := self.conf.frontend["admin_key"]
  if ok {
    // TODO: check for valid format
    log.Println("add admin key", pubkey)
    err = self.database.MarkModPubkeyGlobal(pubkey)
    if err != nil {
      log.Printf("failed to add admin mod key, %s", err)
    }
  }

  defer self.listener.Close()
  // run expiration mainloop
  go self.expire.Mainloop()
  // we are now running
  self.running = true

  // persist outfeeds
  for idx := range self.conf.feeds {
    go self.persistFeed(self.conf.feeds[idx], "reader")
    go self.persistFeed(self.conf.feeds[idx], "stream")
  }

  // start accepting incoming connections
  go self.acceptloop()

  go func () {
    // if we have no initial posts create one
    if self.database.ArticleCount() == 0 {
      nntp := newPlaintextArticle("welcome to nntpchan, this post was inserted on startup automatically", "system@"+self.instance_name, "Welcome to NNTPChan", "system", self.instance_name, genMessageID(self.instance_name), "overchan.test")
      nntp.Pack()
      file := self.store.CreateTempFile(nntp.MessageID())
      if file != nil {
        err := self.store.WriteMessage(nntp, file)
        file.Close()
        if err == nil {
          self.infeed <- nntp
        } else {
          log.Println("failed to create startup messge?", err)
        }
      }
    }
  }()

  // get all pending articles from infeed and load them
  go func() {
    f, err := os.Open(self.store.TempDir())
    if err == nil {
      names, err := f.Readdirnames(0)
      if err == nil {
        for _, name := range names {
          self.infeed_load <- name
        }
      }
    }

  }()

  // if we have no frontend this does nothing
  if self.frontend != nil {
    go self.pollfrontend()
  }
  go self.pollinfeed()
  go self.pollmessages()
  self.polloutfeeds()
}

func (self NNTPDaemon) pollfrontend() {
  chnl := self.frontend.NewPostsChan()
  for {
    nntp := <- chnl
    // new post from frontend
    log.Println("frontend post", nntp.MessageID())
    self.infeed <- nntp
  }
}
func (self NNTPDaemon) pollinfeed() {
  for {
    msgid := <- self.infeed_load
    log.Println("load from infeed", msgid)
    msg := self.store.ReadTempMessage(msgid)
    if msg != nil {
      self.infeed <- msg
    }
  }
}

func (self NNTPDaemon) polloutfeeds() {

  for {
    select {

    case outfeed := <- self.register_outfeed:
      log.Println("outfeed", outfeed.name, "registered")
      self.feeds[outfeed.name] = outfeed
    case outfeed := <- self.deregister_outfeed:
      log.Println("outfeed", outfeed.name, "de-registered")
      delete(self.feeds, outfeed.name)
    case nntp := <- self.send_all_feeds:
      log.Println("federate", nntp.MessageID())
      for _, feed := range self.feeds {
        log.Println("mode", feed.mode)
        if feed.policy.AllowsNewsgroup(nntp.Newsgroup()) && feed.mode != "READER" {
          feed.check <- nntp.MessageID()
        }
      }
    case nntp := <- self.ask_for_article:
      for _, feed := range self.feeds {
        if feed.policy.AllowsNewsgroup(nntp.Newsgroup()) && feed.mode == "READER" {
          log.Println("asking", feed.name, "for", nntp.MessageID())
          feed.article <- nntp.MessageID()
        }
      }
    }
  }
}

func (self NNTPDaemon) pollmessages() {
  var chnl chan NNTPMessage
  modchnl := self.mod.MessageChan()
  if self.frontend != nil {
    chnl = self.frontend.PostsChan()
  }
  for {

    nntp := <- self.infeed
    // ammend path
    nntp.AppendPath(self.instance_name)
    msgid := nntp.MessageID()
    log.Println("daemon got", msgid)

    // store article and attachments
    // register with database
    // this also generates thumbnails
    self.store.StorePost(nntp)

    ref := nntp.Reference()
    if ref != "" && ValidMessageID(ref) && ! self.database.HasArticleLocal(ref) {
      // we don't have the root post
      // generate it
      //log.Println("creating temp root post for", ref , "in", nntp.Newsgroup())
      //root := newPlaintextArticle("temporary placeholder", "lol@lol", "root post "+ref+" not found", "system", "temp", ref, nntp.Newsgroup())
      //self.store.StorePost(root)
    }

    // prepare for content rollover
    // fallback rollover
    rollover := 100

    group := nntp.Newsgroup()
    tpp, err := self.database.GetThreadsPerPage(group)
    ppb, err := self.database.GetPagesPerBoard(group)
    if err == nil {
      rollover = tpp * ppb
    }

    // roll over old content
    self.expire.ExpireGroup(group, rollover)
    // handle mod events
    if group == "ctl" {
      modchnl <- nntp
    }

    // queue to all outfeeds
    // XXX: blocking ?
    self.send_all_feeds <- ArticleEntry{msgid, group}
    // tell frontend
    // XXX: blocking ?
    if chnl != nil {
      if self.frontend.AllowNewsgroup(group) {
        chnl <- nntp
      } else {
        log.Println("frontend does not allow", group, "not sending")
      }
    }
  }
}

func (self NNTPDaemon) acceptloop() {
  for {
    // accept
    conn, err := self.listener.Accept()
    if err != nil {
      log.Fatal(err)
    }
    // make a new inbound nntp connection handler
    nntp := createNNTPConnection()
    c := textproto.NewConn(conn)
    // send banners and shit
    err = nntp.inboundHandshake(c)
    if err == nil {
      // run, we support stream and reader
      go nntp.runConnection(self, true, true, true, c)
    } else {
      log.Println("failed to send banners", err)
      c.Close()
    }
  }
}

func (self NNTPDaemon) Setup() NNTPDaemon {
  log.Println("checking for configs...")
  // check that are configs exist
  CheckConfig()
  log.Println("loading config...")
  // read the config
  self.conf = ReadConfig()
  if self.conf == nil {
    log.Fatal("failed to load config")
  }
  // validate the config
  log.Println("validating configs...")
  self.conf.Validate()
  log.Println("configs are valid")

  db_host := self.conf.database["host"]
  db_port := self.conf.database["port"]
  db_user := self.conf.database["user"]
  db_passwd := self.conf.database["password"]

  // set up database stuff
  log.Println("connecting to database...")
  self.database = NewDatabase(self.conf.database["type"], self.conf.database["schema"], db_host, db_port, db_user, db_passwd)
  log.Println("ensure that the database is created...")
  self.database.CreateTables()

  // set up store
  log.Println("set up article store...")
  self.store = createArticleStore(self.conf.store, self.database)

  self.mod = modEngine{
    store: self.store,
    database:  self.database,
    chnl: make(chan NNTPMessage),
  }
  return self
}
<commit_msg>register outfeed elsewhere<commit_after>//
// daemon.go
//
package srnd
import (
  "log"
  "net"
  "net/textproto"
  "strconv"
  "strings"
  "os"
  "time"
)

type NNTPDaemon struct {
  instance_name string
  bind_addr string
  conf *SRNdConfig
  store ArticleStore
  database Database
  mod ModEngine
  expire ExpirationCore
  listener net.Listener
  debug bool
  sync_on_start bool
  // anon settings
  allow_anon bool
  allow_anon_attachments bool

  running bool
  // http frontend
  frontend Frontend

  // map of addr -> NNTPConnection
  feeds map[string]nntpConnection
  // for registering and deregistering outbound feeds
  register_outfeed chan nntpConnection
  deregister_outfeed chan nntpConnection
  // infeed for articles
  infeed chan NNTPMessage
  // channel to load messages to infeed given their message id
  infeed_load chan string
  // channel for broadcasting a message to all feeds given their newsgroup, message_id
  send_all_feeds chan ArticleEntry
  // channel for broadcasting an ARTICLE command to all feeds in reader mode
  ask_for_article chan ArticleEntry
}

func (self NNTPDaemon) End() {
  self.listener.Close()
}

func (self NNTPDaemon) persistFeed(conf FeedConfig, mode string) {
  for {
    if self.running {

      var conn net.Conn
      var err error
      proxy_type := strings.ToLower(conf.proxy_type)

      if proxy_type ==  "" || proxy_type == "none" {
        // connect out without proxy
        log.Println("dial out to ", conf.addr)
        conn, err = net.Dial("tcp", conf.addr)
        if err != nil {
          log.Println("cannot connect to outfeed", conf.addr, err)
					time.Sleep(time.Second * 5)
          continue
        }
      } else if proxy_type == "socks4a" {
        // connect via socks4a
        log.Println("dial out via proxy", conf.proxy_addr)
        conn, err = net.Dial("tcp", conf.proxy_addr)
        if err != nil {
          log.Println("cannot connect to proxy", conf.proxy_addr)
					time.Sleep(time.Second * 5)
          continue
        }
        // generate request
        idx := strings.LastIndex(conf.addr, ":")
        if idx == -1 {
          log.Fatal("invalid outfeed address")
        }
        var port uint64
        addr := conf.addr[:idx]
        port, err = strconv.ParseUint(conf.addr[idx+1:], 10, 16)
        if port >= 25536 {
          log.Fatal("bad proxy port" , port)
        }
        var proxy_port uint16
        proxy_port = uint16(port)
        proxy_ident := "srndv2"
        req_len := len(addr) + 1 + len(proxy_ident) + 1 + 8

        req := make([]byte, req_len)
        // pack request
        req[0] = '\x04'
        req[1] = '\x01'
        req[2] = byte(proxy_port & 0xff00 >> 8)
        req[3] = byte(proxy_port & 0x00ff)
        req[7] = '\x01'
        idx = 8

        proxy_ident_b := []byte(proxy_ident)
        addr_b := []byte(addr)

        var bi int
        for bi = range proxy_ident_b {
          req[idx] = proxy_ident_b[bi]
          idx += 1
        }
        idx += 1
        for bi = range addr_b {
          req[idx] = addr_b[bi]
          idx += 1
        }

        // send request
        conn.Write(req)
        resp := make([]byte, 8)

        // receive response
        conn.Read(resp)
        if resp[1] == '\x5a' {
          // success
          log.Println("connected to", conf.addr)
        } else {
          log.Println("failed to connect to", conf.addr)
					time.Sleep(time.Second * 5)
          continue
        }
      }
      nntp := createNNTPConnection()
      nntp.policy = conf.policy
      nntp.name = conf.addr
      c := textproto.NewConn(conn)
      stream, reader, err := nntp.outboundHandshake(c)
      if err == nil {
        if self.sync_on_start {
          go func() {
            log.Println(nntp.name, "will do full sync")
            for _, article := range self.database.GetAllArticles() {
              if nntp.policy.AllowsNewsgroup(article.Newsgroup()) {
                nntp.check <- article.MessageID()
              }
            }

          }()
        }
        // don't use streaming if we have set mode reader
        ok, err := nntp.modeSwitch(mode, c)
        if ok {
          self.register_outfeed <- nntp
          nntp.runConnection(self, false, stream, reader, c)
        } else {
          log.Println("failed to switch modes", err)
        }
        self.deregister_outfeed <- nntp

      } else {
        log.Println("error doing outbound hanshake", err)
      }
    }
  }
  time.Sleep(1 * time.Second)
}

// run daemon
func (self NNTPDaemon) Run() {

  self.bind_addr = self.conf.daemon["bind"]

  listener , err := net.Listen("tcp", self.bind_addr)
  if err != nil {
    log.Fatal("failed to bind to", self.bind_addr, err)
  }
  self.listener = listener
  log.Printf("SRNd NNTPD bound at %s", listener.Addr())

  self.register_outfeed = make(chan nntpConnection)
  self.deregister_outfeed = make(chan nntpConnection)
  self.infeed = make(chan NNTPMessage, 8)
  self.infeed_load = make(chan string)
  self.send_all_feeds = make(chan ArticleEntry, 64)
  self.feeds = make(map[string]nntpConnection)
  self.ask_for_article = make(chan ArticleEntry, 64)

  self.expire = createExpirationCore(self.database, self.store)
  self.sync_on_start = self.conf.daemon["sync_on_start"] == "1"
  self.debug = self.conf.daemon["log"] == "debug"
  self.instance_name = self.conf.daemon["instance_name"]
  self.allow_anon = self.conf.daemon["allow_anon"] == "1"
  self.allow_anon_attachments = self.conf.daemon["allow_anon_attachments"] == "1"

  if self.debug {
    log.Println("debug mode activated")
  }

  // do we enable the frontend?
  if self.conf.frontend["enable"] == "1" {
    log.Printf("frontend %s enabled", self.conf.frontend["name"])
    http_frontend := NewHTTPFrontend(&self, self.conf.frontend, self.conf.worker["url"])
    nntp_frontend := NewNNTPFrontend(&self, self.conf.frontend["nntp"])
    self.frontend = MuxFrontends(http_frontend, nntp_frontend)
    go self.frontend.Mainloop()
  }

  // set up admin user if it's specified in the config
  pubkey , ok := self.conf.frontend["admin_key"]
  if ok {
    // TODO: check for valid format
    log.Println("add admin key", pubkey)
    err = self.database.MarkModPubkeyGlobal(pubkey)
    if err != nil {
      log.Printf("failed to add admin mod key, %s", err)
    }
  }

  defer self.listener.Close()
  // run expiration mainloop
  go self.expire.Mainloop()
  // we are now running
  self.running = true

  // persist outfeeds
  for idx := range self.conf.feeds {
    go self.persistFeed(self.conf.feeds[idx], "reader")
    go self.persistFeed(self.conf.feeds[idx], "stream")
  }

  // start accepting incoming connections
  go self.acceptloop()

  go func () {
    // if we have no initial posts create one
    if self.database.ArticleCount() == 0 {
      nntp := newPlaintextArticle("welcome to nntpchan, this post was inserted on startup automatically", "system@"+self.instance_name, "Welcome to NNTPChan", "system", self.instance_name, genMessageID(self.instance_name), "overchan.test")
      nntp.Pack()
      file := self.store.CreateTempFile(nntp.MessageID())
      if file != nil {
        err := self.store.WriteMessage(nntp, file)
        file.Close()
        if err == nil {
          self.infeed <- nntp
        } else {
          log.Println("failed to create startup messge?", err)
        }
      }
    }
  }()

  // get all pending articles from infeed and load them
  go func() {
    f, err := os.Open(self.store.TempDir())
    if err == nil {
      names, err := f.Readdirnames(0)
      if err == nil {
        for _, name := range names {
          self.infeed_load <- name
        }
      }
    }

  }()

  // if we have no frontend this does nothing
  if self.frontend != nil {
    go self.pollfrontend()
  }
  go self.pollinfeed()
  go self.pollmessages()
  self.polloutfeeds()
}

func (self NNTPDaemon) pollfrontend() {
  chnl := self.frontend.NewPostsChan()
  for {
    nntp := <- chnl
    // new post from frontend
    log.Println("frontend post", nntp.MessageID())
    self.infeed <- nntp
  }
}
func (self NNTPDaemon) pollinfeed() {
  for {
    msgid := <- self.infeed_load
    log.Println("load from infeed", msgid)
    msg := self.store.ReadTempMessage(msgid)
    if msg != nil {
      self.infeed <- msg
    }
  }
}

func (self NNTPDaemon) polloutfeeds() {

  for {
    select {

    case outfeed := <- self.register_outfeed:
      log.Println("outfeed", outfeed.name, "registered")
      self.feeds[outfeed.name] = outfeed
    case outfeed := <- self.deregister_outfeed:
      log.Println("outfeed", outfeed.name, "de-registered")
      delete(self.feeds, outfeed.name)
    case nntp := <- self.send_all_feeds:
      log.Println("federate", nntp.MessageID())
      for _, feed := range self.feeds {
        log.Println("mode", feed.mode)
        if feed.policy.AllowsNewsgroup(nntp.Newsgroup()) && feed.mode != "READER" {
          feed.check <- nntp.MessageID()
        }
      }
    case nntp := <- self.ask_for_article:
      for _, feed := range self.feeds {
        if feed.policy.AllowsNewsgroup(nntp.Newsgroup()) && feed.mode == "READER" {
          log.Println("asking", feed.name, "for", nntp.MessageID())
          feed.article <- nntp.MessageID()
        }
      }
    }
  }
}

func (self NNTPDaemon) pollmessages() {
  var chnl chan NNTPMessage
  modchnl := self.mod.MessageChan()
  if self.frontend != nil {
    chnl = self.frontend.PostsChan()
  }
  for {

    nntp := <- self.infeed
    // ammend path
    nntp.AppendPath(self.instance_name)
    msgid := nntp.MessageID()
    log.Println("daemon got", msgid)

    // store article and attachments
    // register with database
    // this also generates thumbnails
    self.store.StorePost(nntp)

    ref := nntp.Reference()
    if ref != "" && ValidMessageID(ref) && ! self.database.HasArticleLocal(ref) {
      // we don't have the root post
      // generate it
      //log.Println("creating temp root post for", ref , "in", nntp.Newsgroup())
      //root := newPlaintextArticle("temporary placeholder", "lol@lol", "root post "+ref+" not found", "system", "temp", ref, nntp.Newsgroup())
      //self.store.StorePost(root)
    }

    // prepare for content rollover
    // fallback rollover
    rollover := 100

    group := nntp.Newsgroup()
    tpp, err := self.database.GetThreadsPerPage(group)
    ppb, err := self.database.GetPagesPerBoard(group)
    if err == nil {
      rollover = tpp * ppb
    }

    // roll over old content
    self.expire.ExpireGroup(group, rollover)
    // handle mod events
    if group == "ctl" {
      modchnl <- nntp
    }

    // queue to all outfeeds
    // XXX: blocking ?
    self.send_all_feeds <- ArticleEntry{msgid, group}
    // tell frontend
    // XXX: blocking ?
    if chnl != nil {
      if self.frontend.AllowNewsgroup(group) {
        chnl <- nntp
      } else {
        log.Println("frontend does not allow", group, "not sending")
      }
    }
  }
}

func (self NNTPDaemon) acceptloop() {
  for {
    // accept
    conn, err := self.listener.Accept()
    if err != nil {
      log.Fatal(err)
    }
    // make a new inbound nntp connection handler
    nntp := createNNTPConnection()
    c := textproto.NewConn(conn)
    // send banners and shit
    err = nntp.inboundHandshake(c)
    if err == nil {
      // run, we support stream and reader
      go nntp.runConnection(self, true, true, true, c)
    } else {
      log.Println("failed to send banners", err)
      c.Close()
    }
  }
}

func (self NNTPDaemon) Setup() NNTPDaemon {
  log.Println("checking for configs...")
  // check that are configs exist
  CheckConfig()
  log.Println("loading config...")
  // read the config
  self.conf = ReadConfig()
  if self.conf == nil {
    log.Fatal("failed to load config")
  }
  // validate the config
  log.Println("validating configs...")
  self.conf.Validate()
  log.Println("configs are valid")

  db_host := self.conf.database["host"]
  db_port := self.conf.database["port"]
  db_user := self.conf.database["user"]
  db_passwd := self.conf.database["password"]

  // set up database stuff
  log.Println("connecting to database...")
  self.database = NewDatabase(self.conf.database["type"], self.conf.database["schema"], db_host, db_port, db_user, db_passwd)
  log.Println("ensure that the database is created...")
  self.database.CreateTables()

  // set up store
  log.Println("set up article store...")
  self.store = createArticleStore(self.conf.store, self.database)

  self.mod = modEngine{
    store: self.store,
    database:  self.database,
    chnl: make(chan NNTPMessage),
  }
  return self
}
<|endoftext|>


<commit_before>package main

import (
  "bytes"
  "fmt"
  "net/http"
  "io/ioutil"
  "log"
  "encoding/json"
  "io"
  // "errors"
)

// STRUCTS

type Client struct {
  Url string
}

// http://docs.couchdb.org/en/latest/intro/api.html#server
type Server struct {
  Couchdb string
  Uuid string
  Vendor struct {
    Version string
    Name string
  }
  Version string
}

type Database struct {
  Url string
}

type DatabaseInfo struct {
  Name string `json:"db_name"`
  DocCount int `json:"doc_count"`
  DocDelCount int `json:"doc_del_count"`
}

type DbResponse struct {
  Ok bool
  Error string
  Reason string
}

type DocResponse struct {
  Ok bool
  Id string
  Rev string
  Error string
  Reason string
}

type Error struct {
  Method string
  Url string
  StatusCode int
  Type string `json:"error"`
  Reason string
}

// custom Error struct has to implement Error method
func (e *Error) Error() string {
  return "CouchDB: " + e.Type + " - " + e.Reason
}

// CLIENT OPERATIONS

/**
 * Get server information.
 */
func (c *Client) info() (*Server, error) {
  body, err := request("GET", c.Url, nil)
  if err != nil {
    return nil, err
  }
  var server *Server
  err = json.Unmarshal(body, &server)
  if err != nil {
    return nil, err
  }
  return server, nil
}

/**
 * Get all databases.
 */
func (c *Client) all() ([]string, error) {
  body, err := request("GET", c.Url + "_all_dbs", nil)
  if err != nil {
    return nil, err
  }
  var data []string
  return data, json.Unmarshal(body, &data)
}

/**
 * Get single database.
 */
func (c *Client) get(name string) (*DatabaseInfo, error) {
  body, err := request("GET", c.Url + name, nil)
  if err != nil {
    return nil, err
  }
  var dbInfo *DatabaseInfo
  return dbInfo, json.Unmarshal(body, &dbInfo)
}

/**
 * Create single database.
 */
func (c *Client) create(name string) (*DbResponse, error) {
  body, err := request("PUT", c.Url + name, nil)
  if err != nil {
    return nil, err
  }
  var DbResponse *DbResponse
  return DbResponse, json.Unmarshal(body, &DbResponse)
}

/**
 * Delete single database.
 */
func (c *Client) delete(name string) (*DbResponse, error) {
  body, err := request("DELETE", c.Url + name, nil)
  if err != nil {
    return nil, err
  }
  var DbResponse *DbResponse
  return DbResponse, json.Unmarshal(body, &DbResponse)
}

func (c *Client) use(name string) (Database) {
  return Database{c.Url + "/" + name + "/"}
}

// DATABASE OPERATIONS

/**
 * Head request.
 * http://docs.couchdb.org/en/latest/api/document/common.html#head--db-docid
 */
func (db *Database) head(id string) (*http.Response, error) {
  return http.Head(db.Url + id)
}

func (db *Database) get(id string) (map[string]interface{}, error) {
  body, err := request("GET", db.Url + id, nil)
  if err != nil {
    return nil, err
  }
  var data map[string]interface{}
  return data, json.Unmarshal(body, &data)
}

func (db *Database) put(id string, document interface{}) (*DocResponse, error) {
  data, err := marshal(document)
  if err != nil {
    return nil, err
  }
  body, err := request("PUT", db.Url + id, data)
  if err != nil {
    return nil, err
  }
  var res *DocResponse
  return res, json.Unmarshal(body, &res)
}

// FUNC MAIN

func main() {

  const url = "http://127.0.0.1:5984/"

  // create client
  client := &Client{url}

  // get server info
  // couch, err := client.info()
  // if err != nil {
  //   log.Fatal(err)
  // }
  // fmt.Println(couch.Vendor.Version)

  // get all dbs
  // res, err := client.all()
  // if err != nil {
  //   log.Fatal(err)
  // }
  // fmt.Println(res)

  // get db information
  // info, err := client.get("nice")
  // if err != nil {
  //   log.Fatal(err)
  // }
  // fmt.Println(info)

  // use db
  db := client.use("nice")

  // get document head
  // head, err := db.head("awesome")
  // if err != nil {
  //   log.Fatal(err)
  // }
  // fmt.Println(head.StatusCode)

  // get document
  // doc, err := db.get("awesome")
  // if err != nil {
  //   log.Fatal(err)
  // }
  // nested := doc["nested"].(map[string]interface{})
  // fmt.Println(nested["awesome"])

  // put document
  type MyDoc struct {
    Brand string `json:"brand"`
  }
  myDoc := MyDoc{"audi"}
  _, err := db.put("tight", myDoc)
  if err != nil {
    fmt.Println(err.Type)
    log.Fatal(err)
  }

  //
  // // create db
  // status, err := client.create("nice")
  // if err != nil {
  //   log.Fatal(err)
  // }
  // fmt.Println(status)
  // fmt.Println(status.Ok)
  //
  // // delete database
  // status, err = client.delete("awesome")
  // if err != nil {
  //   log.Fatal(err)
  // }
  // fmt.Println(status)
}

// PROBLEM
// return normal error vs return custom Error struct

// HELPER FUNCTIONS
func request(method, url string, data io.Reader) ([]byte, error) {
  client := &http.Client{}
  req, err := http.NewRequest(method, url, data)
  if err != nil {
    return nil, err
  }
  res, err := client.Do(req)
  if err != nil {
    return nil, err
  }
  defer res.Body.Close()
  body, err := ioutil.ReadAll(res.Body)
  if err != nil {
    return nil, err
  }
  // handle CouchDB http errors
  var error *Error
  err = json.Unmarshal(body, &error)
  if err != nil {
    return nil, err
  }
  if error.Type != "" && error.Reason != "" {
    fmt.Println(method)
    error.Method = method
    error.Url = url
    error.StatusCode = res.StatusCode
    return nil, error
  }
  return body, nil
}

func marshal(v interface{}) (io.Reader, error) {
  json, err := json.Marshal(v)
  if err != nil {
    return nil, err
  }
  return bytes.NewReader(json), nil
}
<commit_msg>improve error method<commit_after>package main

import (
  "bytes"
  "fmt"
  "net/http"
  "io/ioutil"
  "log"
  "encoding/json"
  "io"
  // "errors"
)

// STRUCTS

type Client struct {
  Url string
}

// http://docs.couchdb.org/en/latest/intro/api.html#server
type Server struct {
  Couchdb string
  Uuid string
  Vendor struct {
    Version string
    Name string
  }
  Version string
}

type Database struct {
  Url string
}

type DatabaseInfo struct {
  Name string `json:"db_name"`
  DocCount int `json:"doc_count"`
  DocDelCount int `json:"doc_del_count"`
}

type DbResponse struct {
  Ok bool
  Error string
  Reason string
}

type DocResponse struct {
  Ok bool
  Id string
  Rev string
  Error string
  Reason string
}

type Error struct {
  Method string
  Url string
  StatusCode int
  Type string `json:"error"`
  Reason string
}

// custom Error struct has to implement Error method
func (e *Error) Error() string {
  return fmt.Sprintf("CouchDB - %s %s, Status Code: %d, Error: %s, Reason: %s", e.Method, e.Url, e.StatusCode, e.Type, e.Reason)
}

// CLIENT OPERATIONS

/**
 * Get server information.
 */
func (c *Client) info() (*Server, error) {
  body, err := request("GET", c.Url, nil)
  if err != nil {
    return nil, err
  }
  var server *Server
  err = json.Unmarshal(body, &server)
  if err != nil {
    return nil, err
  }
  return server, nil
}

/**
 * Get all databases.
 */
func (c *Client) all() ([]string, error) {
  body, err := request("GET", c.Url + "_all_dbs", nil)
  if err != nil {
    return nil, err
  }
  var data []string
  return data, json.Unmarshal(body, &data)
}

/**
 * Get single database.
 */
func (c *Client) get(name string) (*DatabaseInfo, error) {
  body, err := request("GET", c.Url + name, nil)
  if err != nil {
    return nil, err
  }
  var dbInfo *DatabaseInfo
  return dbInfo, json.Unmarshal(body, &dbInfo)
}

/**
 * Create single database.
 */
func (c *Client) create(name string) (*DbResponse, error) {
  body, err := request("PUT", c.Url + name, nil)
  if err != nil {
    return nil, err
  }
  var DbResponse *DbResponse
  return DbResponse, json.Unmarshal(body, &DbResponse)
}

/**
 * Delete single database.
 */
func (c *Client) delete(name string) (*DbResponse, error) {
  body, err := request("DELETE", c.Url + name, nil)
  if err != nil {
    return nil, err
  }
  var DbResponse *DbResponse
  return DbResponse, json.Unmarshal(body, &DbResponse)
}

func (c *Client) use(name string) (Database) {
  return Database{c.Url + name + "/"}
}

// DATABASE OPERATIONS

/**
 * Head request.
 * http://docs.couchdb.org/en/latest/api/document/common.html#head--db-docid
 */
func (db *Database) head(id string) (*http.Response, error) {
  return http.Head(db.Url + id)
}

func (db *Database) get(id string) (map[string]interface{}, error) {
  body, err := request("GET", db.Url + id, nil)
  if err != nil {
    return nil, err
  }
  var data map[string]interface{}
  return data, json.Unmarshal(body, &data)
}

func (db *Database) put(id string, document interface{}) (*DocResponse, error) {
  data, err := marshal(document)
  if err != nil {
    return nil, err
  }
  body, err := request("PUT", db.Url + id, data)
  if err != nil {
    return nil, err
  }
  var res *DocResponse
  return res, json.Unmarshal(body, &res)
}

// FUNC MAIN

func main() {

  const url = "http://127.0.0.1:5984/"

  // create client
  client := &Client{url}

  // get server info
  // couch, err := client.info()
  // if err != nil {
  //   log.Fatal(err)
  // }
  // fmt.Println(couch.Vendor.Version)

  // get all dbs
  // res, err := client.all()
  // if err != nil {
  //   log.Fatal(err)
  // }
  // fmt.Println(res)

  // get db information
  // info, err := client.get("nice")
  // if err != nil {
  //   log.Fatal(err)
  // }
  // fmt.Println(info)

  // use db
  db := client.use("nice")

  // get document head
  // head, err := db.head("awesome")
  // if err != nil {
  //   log.Fatal(err)
  // }
  // fmt.Println(head.StatusCode)

  // get document
  // doc, err := db.get("awesome")
  // if err != nil {
  //   log.Fatal(err)
  // }
  // nested := doc["nested"].(map[string]interface{})
  // fmt.Println(nested["awesome"])

  // put document
  type MyDoc struct {
    Brand string `json:"brand"`
  }
  myDoc := MyDoc{"audi"}
  _, err := db.put("tight", myDoc)
  if err != nil {
    // fmt.Println(err.Type)
    log.Fatal(err)
  }

  //
  // // create db
  // status, err := client.create("nice")
  // if err != nil {
  //   log.Fatal(err)
  // }
  // fmt.Println(status)
  // fmt.Println(status.Ok)
  //
  // // delete database
  // status, err = client.delete("awesome")
  // if err != nil {
  //   log.Fatal(err)
  // }
  // fmt.Println(status)
}

// PROBLEM
// return normal error vs return custom Error struct

// HELPER FUNCTIONS
func request(method, url string, data io.Reader) ([]byte, error) {
  client := &http.Client{}
  req, err := http.NewRequest(method, url, data)
  if err != nil {
    return nil, err
  }
  res, err := client.Do(req)
  if err != nil {
    return nil, err
  }
  defer res.Body.Close()
  body, err := ioutil.ReadAll(res.Body)
  if err != nil {
    return nil, err
  }
  // handle CouchDB http errors
  var error *Error
  err = json.Unmarshal(body, &error)
  if err != nil {
    return nil, err
  }
  if error.Type != "" && error.Reason != "" {
    error.Method = method
    error.Url = url
    error.StatusCode = res.StatusCode
    return nil, error
  }
  return body, nil
}

func marshal(v interface{}) (io.Reader, error) {
  json, err := json.Marshal(v)
  if err != nil {
    return nil, err
  }
  return bytes.NewReader(json), nil
}
<|endoftext|>


<commit_before>// Copyright ©2012 The bíogo.graph 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 graph

import (
	"errors"
)

var notFound = errors.New("graph: target not found") // TODO: Remove this. Just return nil *Node when not found.

// Visit is a function type that is used by a BreadthFirst or DepthFirst to allow side-effects
// on visiting new nodes in a graph traversal.
type Visit func(u, v Node)

// BreadthFirst is a type that can perform a breadth-first search on a graph.
type BreadthFirst struct {
	q      *queue
	visits []bool
}

// NewBreadthFirst creates a new BreadthFirst searcher.
func NewBreadthFirst() *BreadthFirst {
	return &BreadthFirst{q: &queue{}}
}

// Search searches a graph starting from node s until the NodeFilter function nf returns a value of
// true, traversing edges in the graph that allow the Edgefilter function ef to return true. On success
// the terminating node, t is returned. If vo is not nil, it is called with the start and end nodes of an
// edge when the end node has not already been visited. If no node is found that satisfies nf, an error
// is returned.
func (b *BreadthFirst) Search(s Node, ef EdgeFilter, nf NodeFilter, vo Visit) (Node, error) {
	b.q.Enqueue(s)
	b.visits = mark(s, b.visits)
	for b.q.Len() > 0 {
		t, err := b.q.Dequeue()
		if err != nil {
			return nil, err // FIXME: Can replace this with panic when notFound is removed.
		}
		if nf(t) {
			return t, nil
		}
		for _, n := range t.Neighbors(ef) {
			if !b.Visited(n) {
				if vo != nil {
					vo(t, n)
				}
				b.visits = mark(n, b.visits)
				b.q.Enqueue(n)
			}
		}
	}

	return nil, notFound
}

// Visited marks the node n as having been visited by the sercher.
func (b *BreadthFirst) Visited(n Node) bool {
	id := n.ID()
	if id < 0 || id >= len(b.visits) {
		return false
	}
	return b.visits[id]
}

// Reset clears the search queue and visited list.
func (b *BreadthFirst) Reset() {
	b.q.Clear()
	b.visits = b.visits[:0]
}

// DepthFirst is a type that can perform a depth-first search on a graph.
type DepthFirst struct {
	s      *stack
	visits []bool
}

// NewDepthFirst creates a new DepthFirst searcher.
func NewDepthFirst() *DepthFirst {
	return &DepthFirst{s: &stack{}}
}

// Search searches a graph starting from node s until the NodeFilter function nf returns a value of
// true, traversing edges in the graph that allow the Edgefilter function ef to return true. On success
// the terminating node, t is returned. If vo is not nil, it is called with the start and end nodes of an
// edge when the end node has not already been visited. If no node is found that satisfies nf, an error
// is returned.
func (d *DepthFirst) Search(s Node, ef EdgeFilter, nf NodeFilter, vo Visit) (Node, error) {
	d.s.Push(s)
	d.visits = mark(s, d.visits)
	for d.s.Len() > 0 {
		t, err := d.s.Pop()
		if err != nil {
			return nil, err // FIXME: Can replace this with panic when notFound is removed.
		}
		if nf(t) {
			return t, nil
		}
		for _, n := range t.Neighbors(ef) {
			if !d.Visited(n) {
				if vo != nil {
					vo(t, n)
				}
				d.visits = mark(n, d.visits)
				d.s.Push(n)
			}
		}
	}

	return nil, notFound
}

// Visited marks the node n as having been visited by the searcher.
func (d *DepthFirst) Visited(n Node) bool {
	id := n.ID()
	if id < 0 || id >= len(d.visits) {
		return false
	}
	return d.visits[id]
}

// Reset clears the search stack and visited list.
func (d *DepthFirst) Reset() {
	d.s.Clear()
	d.visits = d.visits[:0]
}

func mark(n Node, v []bool) []bool {
	id := n.ID()
	if id == len(v) {
		v = append(v, true)
	} else if id > len(v) {
		t := make([]bool, id+1)
		copy(t, v)
		v = t
		v[id] = true
	} else {
		v[id] = true
	}

	return v
}
<commit_msg>Clean up traversal a little<commit_after>// Copyright ©2012 The bíogo.graph 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 graph

// Visit is a function type that is used by a BreadthFirst or DepthFirst to allow side-effects
// on visiting new nodes in a graph traversal.
type Visit func(u, v Node)

// BreadthFirst is a type that can perform a breadth-first search on a graph.
type BreadthFirst struct {
	q      *queue
	visits []bool
}

// NewBreadthFirst creates a new BreadthFirst searcher.
func NewBreadthFirst() *BreadthFirst {
	return &BreadthFirst{q: &queue{}}
}

// Search searches a graph starting from node s until the NodeFilter function nf returns a value of
// true, traversing edges in the graph that allow the Edgefilter function ef to return true. On success
// the terminating node, t is returned. If vo is not nil, it is called with the start and end nodes of an
// edge when the end node has not already been visited.
func (b *BreadthFirst) Search(s Node, ef EdgeFilter, nf NodeFilter, vo Visit) Node {
	b.q.Enqueue(s)
	b.visits = mark(s, b.visits)
	for b.q.Len() > 0 {
		t, err := b.q.Dequeue()
		if err != nil {
			panic(err)
		}
		if nf != nil && nf(t) {
			return t
		}
		for _, n := range t.Neighbors(ef) {
			if !b.Visited(n) {
				if vo != nil {
					vo(t, n)
				}
				b.visits = mark(n, b.visits)
				b.q.Enqueue(n)
			}
		}
	}

	return nil
}

// Visited returns whether the node n has been visited by the searcher.
func (b *BreadthFirst) Visited(n Node) bool {
	id := n.ID()
	if id < 0 || id >= len(b.visits) {
		return false
	}
	return b.visits[id]
}

// Reset clears the search queue and visited list.
func (b *BreadthFirst) Reset() {
	b.q.Clear()
	b.visits = b.visits[:0]
}

// DepthFirst is a type that can perform a depth-first search on a graph.
type DepthFirst struct {
	s      *stack
	visits []bool
}

// NewDepthFirst creates a new DepthFirst searcher.
func NewDepthFirst() *DepthFirst {
	return &DepthFirst{s: &stack{}}
}

// Search searches a graph starting from node s until the NodeFilter function nf returns a value of
// true, traversing edges in the graph that allow the Edgefilter function ef to return true. On success
// the terminating node, t is returned. If vo is not nil, it is called with the start and end nodes of an
// edge when the end node has not already been visited.
func (d *DepthFirst) Search(s Node, ef EdgeFilter, nf NodeFilter, vo Visit) Node {
	d.s.Push(s)
	d.visits = mark(s, d.visits)
	for d.s.Len() > 0 {
		t, err := d.s.Pop()
		if err != nil {
			panic(err)
		}
		if nf != nil && nf(t) {
			return t
		}
		for _, n := range t.Neighbors(ef) {
			if !d.Visited(n) {
				if vo != nil {
					vo(t, n)
				}
				d.visits = mark(n, d.visits)
				d.s.Push(n)
			}
		}
	}

	return nil
}

// Visited returns whether the node n has been visited by the searcher.
func (d *DepthFirst) Visited(n Node) bool {
	id := n.ID()
	if id < 0 || id >= len(d.visits) {
		return false
	}
	return d.visits[id]
}

// Reset clears the search stack and visited list.
func (d *DepthFirst) Reset() {
	d.s.Clear()
	d.visits = d.visits[:0]
}

func mark(n Node, v []bool) []bool {
	id := n.ID()
	switch {
	case id == len(v):
		v = append(v, true)
	case id > len(v):
		t := make([]bool, id+1)
		copy(t, v)
		v = t
		v[id] = true
	default:
		v[id] = true
	}
	return v
}
<|endoftext|>


<commit_before>package cli

import (
	log "github.com/Sirupsen/logrus"
	"github.com/bitrise-io/stepman/stepman"
	"github.com/codegangsta/cli"
)

func deleteCollection(c *cli.Context) {
	log.Debugln("[STEPMAN] - Delete collection")

	// Input validation
	collectionURI := c.String(CollectionKey)
	if collectionURI == "" {
		log.Fatalln("[STEPMAN] - No step collection specified")
	}

	route, found := stepman.ReadRoute(collectionURI)
	if !found {
		log.Fatalln("No route found for lib: " + collectionURI)
	}

	if err := stepman.CleanupRoute(route); err != nil {
		log.Errorf("Failed to cleanup route for uri: %s", collectionURI)
	}
}
<commit_msg>don't fail in delete if doesn't exist<commit_after>package cli

import (
	log "github.com/Sirupsen/logrus"
	"github.com/bitrise-io/stepman/stepman"
	"github.com/codegangsta/cli"
)

func deleteCollection(c *cli.Context) {
	log.Debugln("[STEPMAN] - Delete collection")

	// Input validation
	collectionURI := c.String(CollectionKey)
	if collectionURI == "" {
		log.Fatalln("[STEPMAN] - No step collection specified")
	}

	route, found := stepman.ReadRoute(collectionURI)
	if !found {
		log.Warn("No route found for lib: " + collectionURI)
		return
	}

	if err := stepman.CleanupRoute(route); err != nil {
		log.Errorf("Failed to cleanup route for uri: %s", collectionURI)
	}
}
<|endoftext|>


<commit_before>package gocassa

import (
	"bytes"
	"encoding/json"
	"fmt"
	"runtime"
	"strconv"
)

const (
	read = iota
	singleRead
	delete
	update
	insert
)

type op struct {
	qe  QueryExecutor
	ops []singleOp
}

type singleOp struct {
	options Options
	f       filter
	opType  int
	result  interface{}
	m       map[string]interface{} // map for updates, sets etc
}

func newWriteOp(qe QueryExecutor, f filter, opType int, m map[string]interface{}) *op {
	return &op{
		qe: qe,
		ops: []singleOp{
			{
				f:      f,
				opType: opType,
				m:      m,
			},
		},
	}
}

func (w *singleOp) read(qe QueryExecutor, opt Options) error {
	stmt, params := w.generateRead(opt)
	maps, err := qe.Query(stmt, params...)
	if err != nil {
		return err
	}
	bytes, err := json.Marshal(maps)
	if err != nil {
		return err
	}
	return json.Unmarshal(bytes, w.result)
}

func (w *singleOp) readOne(qe QueryExecutor, opt Options) error {
	stmt, params := w.generateRead(opt)
	maps, err := qe.Query(stmt, params...)
	if err != nil {
		return err
	}
	if len(maps) == 0 {
		_, f, n, _ := runtime.Caller(3)
		return RowNotFoundError{
			file: f,
			line: n,
		}
	}
	bytes, err := json.Marshal(maps[0])
	if err != nil {
		return err
	}
	return json.Unmarshal(bytes, w.result)
}

func (w *singleOp) write(qe QueryExecutor, opt Options) error {
	stmt, params := w.generateWrite(opt)
	return qe.Execute(stmt, params...)
}

func (w *singleOp) run(qe QueryExecutor, opt Options) error {
	switch w.opType {
	case update, insert, delete:
		return w.write(qe, opt)
	case read:
		return w.read(qe, opt)
	case singleRead:
		return w.readOne(qe, opt)
	}
	return nil
}

// Noop returns an empty `Op` which is useful to conditionally add `Op`s to.
func Noop() Op {
	return &op{
		qe:  nil,
		ops: []singleOp{},
	}
}

func (w *op) Add(wo ...Op) Op {
	for _, v := range wo {
		w.qe = v.(*op).qe
		w.ops = append(w.ops, v.(*op).ops...)
	}
	return w
}

func (w *op) Run() error {
	for _, v := range w.ops {
		err := v.run(w.qe, v.options)
		if err != nil {
			return err
		}
	}
	return nil
}

func (w *op) WithOptions(opt Options) Op {
	newOps := []singleOp{}
	for _, v := range w.ops {
		newOps = append(newOps, singleOp{
			options: v.options.Merge(opt),
			f:       v.f,
			opType:  v.opType,
			result:  v.result,
			m:       v.m,
		})
	}
	return &op{
		qe:  w.qe,
		ops: newOps,
	}
}

func (w op) RunAtomically() error {
	return fmt.Errorf("Not implemented yet")
	//stmts := []string{}
	//params := [][]interface{}{}
	//for _, vop := range w.ops {
	//	// We are pushing the limits of the type system here...
	//	if vop.opType == update || vop.opType == insert || vop.opType == delete {
	//		stmts = append(stmts, vop.stmt)
	//		params = append(params, vop.params)
	//	}
	//}
	//return w.qe.ExecuteAtomically(stmts, params)
}

func (o *singleOp) generateWrite(opt Options) (string, []interface{}) {
	var str string
	var vals []interface{}
	switch o.opType {
	case update:
		stmt, uvals := updateStatement(o.f.t.keySpace.name, o.f.t.Name(), o.m, o.f.t.options.Merge(opt))
		whereStmt, whereVals := generateWhere(o.f.rs)
		str = stmt + whereStmt
		vals = append(uvals, whereVals...)
	case delete:
		str, vals = generateWhere(o.f.rs)
		str = fmt.Sprintf("DELETE FROM %s.%s%s", o.f.t.keySpace.name, o.f.t.Name(), str)
	case insert:
		fields, insertVals := keyValues(o.m)
		str = insertStatement(o.f.t.keySpace.name, o.f.t.Name(), fields, o.f.t.options.Merge(opt))
		vals = insertVals
	}
	if o.f.t.keySpace.debugMode {
		fmt.Println(str, vals)
	}
	return str, vals
}

func (o *singleOp) generateRead(opt Options) (string, []interface{}) {
	w, wv := generateWhere(o.f.rs)
	ord, ov := o.generateOrderBy()
	lim, lv := o.generateLimit(o.f.t.options.Merge(opt))
	stmt := fmt.Sprintf("SELECT %s FROM %s.%s", o.f.t.generateFieldNames(), o.f.t.keySpace.name, o.f.t.Name())
	vals := []interface{}{}
	buf := new(bytes.Buffer)
	buf.WriteString(stmt)
	if w != "" {
		buf.WriteString(" ")
		buf.WriteString(w)
		vals = append(vals, wv...)
	}
	if ord != "" {
		buf.WriteString(" ")
		buf.WriteString(ord)
		vals = append(vals, ov...)
	}
	if lim != "" {
		buf.WriteString(" ")
		buf.WriteString(lim)
		vals = append(vals, lv...)
	}
	if o.f.t.keySpace.debugMode {
		fmt.Println(buf.String(), vals)
	}
	return buf.String(), vals
}

func (p *singleOp) generateOrderBy() (string, []interface{}) {
	return "", []interface{}{}
	// " ORDER BY %v"
}

func (o *singleOp) generateLimit(opt Options) (string, []interface{}) {
	if opt.Limit < 1 {
		return "", []interface{}{}
	}
	return "LIMIT ?", []interface{}{opt.Limit}
}

func generateWhere(rs []Relation) (string, []interface{}) {
	var (
		vals []interface{}
		buf  = new(bytes.Buffer)
	)

	if len(rs) > 0 {
		buf.WriteString(" WHERE ")
		for i, r := range rs {
			if i > 0 {
				buf.WriteString(" AND ")
			}
			s, v := r.cql()
			buf.WriteString(s)
			vals = append(vals, v...)
		}
	}
	return buf.String(), vals
}

// UPDATE keyspace.Movies SET col1 = val1, col2 = val2
func updateStatement(kn, cfName string, fields map[string]interface{}, opts Options) (string, []interface{}) {
	buf := new(bytes.Buffer)
	buf.WriteString(fmt.Sprintf("UPDATE %s.%s ", kn, cfName))

	// Apply options
	if opts.TTL != 0 {
		buf.WriteString("USING TTL ")
		buf.WriteString(strconv.FormatFloat(opts.TTL.Seconds(), 'f', 0, 64))
		buf.WriteRune(' ')
	}

	buf.WriteString("SET ")
	i := 0
	ret := []interface{}{}
	for k, v := range fields {
		if i > 0 {
			buf.WriteString(", ")
		}
		if mod, ok := v.(Modifier); ok {
			stmt, vals := mod.cql(k)
			buf.WriteString(stmt)
			ret = append(ret, vals...)
		} else {
			buf.WriteString(k + " = ?")
			ret = append(ret, v)
		}
		i++
	}

	return buf.String(), ret
}
<commit_msg>Add noop type to get around interface issues.<commit_after>package gocassa

import (
	"bytes"
	"encoding/json"
	"fmt"
	"runtime"
	"strconv"
)

const (
	read = iota
	singleRead
	delete
	update
	insert
)

type noop struct {
}

type op struct {
	qe  QueryExecutor
	ops []singleOp
}

type singleOp struct {
	options Options
	f       filter
	opType  int
	result  interface{}
	m       map[string]interface{} // map for updates, sets etc
}

func newWriteOp(qe QueryExecutor, f filter, opType int, m map[string]interface{}) *op {
	return &op{
		qe: qe,
		ops: []singleOp{
			{
				f:      f,
				opType: opType,
				m:      m,
			},
		},
	}
}

func (w *singleOp) read(qe QueryExecutor, opt Options) error {
	stmt, params := w.generateRead(opt)
	maps, err := qe.Query(stmt, params...)
	if err != nil {
		return err
	}
	bytes, err := json.Marshal(maps)
	if err != nil {
		return err
	}
	return json.Unmarshal(bytes, w.result)
}

func (w *singleOp) readOne(qe QueryExecutor, opt Options) error {
	stmt, params := w.generateRead(opt)
	maps, err := qe.Query(stmt, params...)
	if err != nil {
		return err
	}
	if len(maps) == 0 {
		_, f, n, _ := runtime.Caller(3)
		return RowNotFoundError{
			file: f,
			line: n,
		}
	}
	bytes, err := json.Marshal(maps[0])
	if err != nil {
		return err
	}
	return json.Unmarshal(bytes, w.result)
}

func (w *singleOp) write(qe QueryExecutor, opt Options) error {
	stmt, params := w.generateWrite(opt)
	return qe.Execute(stmt, params...)
}

func (w *singleOp) run(qe QueryExecutor, opt Options) error {
	switch w.opType {
	case update, insert, delete:
		return w.write(qe, opt)
	case read:
		return w.read(qe, opt)
	case singleRead:
		return w.readOne(qe, opt)
	}
	return nil
}

// Noop returns an empty `Op` which is useful to conditionally add `Op`s to.
func Noop() Op {
	return &noop{}
}

func (w *noop) Add(wo ...Op) Op {
	if len(wo) == 0 {
		return w
	}

	return wo[0].Add(wo[1:]...)
}

func (w *noop) Run() error {
	return nil
}

func (w *noop) RunAtomically() error {
	return nil
}

func (w *noop) WithOptions(_ Options) Op {
	return w
}

func (w *op) Add(wo ...Op) Op {
	for _, v := range wo {
		w.qe = v.(*op).qe
		w.ops = append(w.ops, v.(*op).ops...)
	}
	return w
}

func (w *op) Run() error {
	for _, v := range w.ops {
		err := v.run(w.qe, v.options)
		if err != nil {
			return err
		}
	}
	return nil
}

func (w *op) WithOptions(opt Options) Op {
	newOps := []singleOp{}
	for _, v := range w.ops {
		newOps = append(newOps, singleOp{
			options: v.options.Merge(opt),
			f:       v.f,
			opType:  v.opType,
			result:  v.result,
			m:       v.m,
		})
	}
	return &op{
		qe:  w.qe,
		ops: newOps,
	}
}

func (w op) RunAtomically() error {
	return fmt.Errorf("Not implemented yet")
	//stmts := []string{}
	//params := [][]interface{}{}
	//for _, vop := range w.ops {
	//	// We are pushing the limits of the type system here...
	//	if vop.opType == update || vop.opType == insert || vop.opType == delete {
	//		stmts = append(stmts, vop.stmt)
	//		params = append(params, vop.params)
	//	}
	//}
	//return w.qe.ExecuteAtomically(stmts, params)
}

func (o *singleOp) generateWrite(opt Options) (string, []interface{}) {
	var str string
	var vals []interface{}
	switch o.opType {
	case update:
		stmt, uvals := updateStatement(o.f.t.keySpace.name, o.f.t.Name(), o.m, o.f.t.options.Merge(opt))
		whereStmt, whereVals := generateWhere(o.f.rs)
		str = stmt + whereStmt
		vals = append(uvals, whereVals...)
	case delete:
		str, vals = generateWhere(o.f.rs)
		str = fmt.Sprintf("DELETE FROM %s.%s%s", o.f.t.keySpace.name, o.f.t.Name(), str)
	case insert:
		fields, insertVals := keyValues(o.m)
		str = insertStatement(o.f.t.keySpace.name, o.f.t.Name(), fields, o.f.t.options.Merge(opt))
		vals = insertVals
	}
	if o.f.t.keySpace.debugMode {
		fmt.Println(str, vals)
	}
	return str, vals
}

func (o *singleOp) generateRead(opt Options) (string, []interface{}) {
	w, wv := generateWhere(o.f.rs)
	ord, ov := o.generateOrderBy()
	lim, lv := o.generateLimit(o.f.t.options.Merge(opt))
	stmt := fmt.Sprintf("SELECT %s FROM %s.%s", o.f.t.generateFieldNames(), o.f.t.keySpace.name, o.f.t.Name())
	vals := []interface{}{}
	buf := new(bytes.Buffer)
	buf.WriteString(stmt)
	if w != "" {
		buf.WriteString(" ")
		buf.WriteString(w)
		vals = append(vals, wv...)
	}
	if ord != "" {
		buf.WriteString(" ")
		buf.WriteString(ord)
		vals = append(vals, ov...)
	}
	if lim != "" {
		buf.WriteString(" ")
		buf.WriteString(lim)
		vals = append(vals, lv...)
	}
	if o.f.t.keySpace.debugMode {
		fmt.Println(buf.String(), vals)
	}
	return buf.String(), vals
}

func (p *singleOp) generateOrderBy() (string, []interface{}) {
	return "", []interface{}{}
	// " ORDER BY %v"
}

func (o *singleOp) generateLimit(opt Options) (string, []interface{}) {
	if opt.Limit < 1 {
		return "", []interface{}{}
	}
	return "LIMIT ?", []interface{}{opt.Limit}
}

func generateWhere(rs []Relation) (string, []interface{}) {
	var (
		vals []interface{}
		buf  = new(bytes.Buffer)
	)

	if len(rs) > 0 {
		buf.WriteString(" WHERE ")
		for i, r := range rs {
			if i > 0 {
				buf.WriteString(" AND ")
			}
			s, v := r.cql()
			buf.WriteString(s)
			vals = append(vals, v...)
		}
	}
	return buf.String(), vals
}

// UPDATE keyspace.Movies SET col1 = val1, col2 = val2
func updateStatement(kn, cfName string, fields map[string]interface{}, opts Options) (string, []interface{}) {
	buf := new(bytes.Buffer)
	buf.WriteString(fmt.Sprintf("UPDATE %s.%s ", kn, cfName))

	// Apply options
	if opts.TTL != 0 {
		buf.WriteString("USING TTL ")
		buf.WriteString(strconv.FormatFloat(opts.TTL.Seconds(), 'f', 0, 64))
		buf.WriteRune(' ')
	}

	buf.WriteString("SET ")
	i := 0
	ret := []interface{}{}
	for k, v := range fields {
		if i > 0 {
			buf.WriteString(", ")
		}
		if mod, ok := v.(Modifier); ok {
			stmt, vals := mod.cql(k)
			buf.WriteString(stmt)
			ret = append(ret, vals...)
		} else {
			buf.WriteString(k + " = ?")
			ret = append(ret, v)
		}
		i++
	}

	return buf.String(), ret
}
<|endoftext|>


<commit_before>package killswitch

import (
	"bytes"
	"fmt"
	"strings"
	"time"
)

// CreatePF creates a pf.conf
func (n *Network) CreatePF() {
	var pass bytes.Buffer
	n.PFRules.WriteString(fmt.Sprintf("# %s\n", strings.Repeat("-", 62)))
	n.PFRules.WriteString(fmt.Sprintf("# %s\n", time.Now().Format(time.RFC1123Z)))
	n.PFRules.WriteString("# sudo pfctl -Fa -f ~/.killswitch.pf.conf -e\n")
	n.PFRules.WriteString(fmt.Sprintf("# %s\n", strings.Repeat("-", 62)))

	// create var for interfaces
	for k := range n.UpInterfaces {
		n.PFRules.WriteString(fmt.Sprintf("int_%s = %q\n", k, k))
		pass.WriteString(fmt.Sprintf("pass on $int_%s proto udp to 224.0.0.251 port 5353\n", k))
		pass.WriteString(fmt.Sprintf("pass on $int_%s proto udp from any port 67 to any port 68\n", k))
		pass.WriteString(fmt.Sprintf("pass on $int_%s inet proto icmp all icmp-type 8 code 0\n", k))
		pass.WriteString(fmt.Sprintf("pass on $int_%s proto {tcp, udp} from any to $vpn_ip\n", k))
	}
	// create var for vpn
	for k := range n.P2PInterfaces {
		n.PFRules.WriteString(fmt.Sprintf("vpn_%s = %q\n", k, k))
		pass.WriteString(fmt.Sprintf("pass on $vpn_%s all\n", k))
	}
	// add vpn peer IP
	n.PFRules.WriteString(fmt.Sprintf("vpn_ip = %q\n", n.PeerIP))
	n.PFRules.WriteString("set block-policy drop\n")
	n.PFRules.WriteString("set ruleset-optimization basic\n")
	n.PFRules.WriteString("set skip on lo0\n")
	n.PFRules.WriteString("block all\n")
	n.PFRules.WriteString(pass.String())
}
<commit_msg>improved pf rules<commit_after>package killswitch

import (
	"bytes"
	"fmt"
	"strings"
	"time"
)

// CreatePF creates a pf.conf
func (n *Network) CreatePF() {
	var pass bytes.Buffer
	n.PFRules.WriteString(fmt.Sprintf("# %s\n", strings.Repeat("-", 62)))
	n.PFRules.WriteString(fmt.Sprintf("# %s\n", time.Now().Format(time.RFC1123Z)))
	n.PFRules.WriteString("# sudo pfctl -Fa -f ~/.killswitch.pf.conf -e\n")
	n.PFRules.WriteString(fmt.Sprintf("# %s\n", strings.Repeat("-", 62)))

	// create var for interfaces
	for k := range n.UpInterfaces {
		n.PFRules.WriteString(fmt.Sprintf("int_%s = %q\n", k, k))
		pass.WriteString(fmt.Sprintf("pass on $int_%s proto {tcp,udp} from any port 67:68 to any port 67:68 keep state\n", k))
		pass.WriteString(fmt.Sprintf("pass on $int_%s inet proto icmp all icmp-type 8 code 0\n", k))
		pass.WriteString(fmt.Sprintf("pass on $int_%s proto {tcp, udp} from any to $vpn_ip\n", k))
	}
	// create var for vpn
	for k := range n.P2PInterfaces {
		n.PFRules.WriteString(fmt.Sprintf("vpn_%s = %q\n", k, k))
		pass.WriteString(fmt.Sprintf("pass on $vpn_%s all\n", k))
	}
	// add vpn peer IP
	n.PFRules.WriteString(fmt.Sprintf("vpn_ip = %q\n", n.PeerIP))
	n.PFRules.WriteString("set block-policy drop\n")
	n.PFRules.WriteString("set ruleset-optimization basic\n")
	n.PFRules.WriteString("set skip on lo0\n")
	n.PFRules.WriteString("block all\n")
	n.PFRules.WriteString("pass quick proto {tcp, udp} from any to any port 53 keep state\n")
	n.PFRules.WriteString("pass from any to 255.255.255.255 keep state\n")
	n.PFRules.WriteString("pass from 255.255.255.255 to any keep state\n")
	n.PFRules.WriteString("pass proto udp from any to 224.0.0.0/4 keep state\n")
	n.PFRules.WriteString("pass proto udp from 224.0.0.0/4 to any keep state\n")
	n.PFRules.WriteString(pass.String())
}
<|endoftext|>


<commit_before>package main

import (
  "fmt"
  "net/http"
  "github.com/codegangsta/martini"
  "github.com/codegangsta/martini-contrib/render"
  "github.com/codegangsta/martini-contrib/sessions"
  "os"
  "os/exec"
  "encoding/json"
  "github.com/sirsean/go-mailgun/mailgun"
  "math/rand"
  "log"
  "html/template"
)
const (
  PROD = "Production"
  VERSION = "1.4.1"
)
type Configuration struct
{
  Env string;
  Domain string;
  Port string;
  MG_API_KEY string;
  MG_DOMAIN string;
  CookieSecret string;
}

func loadConfiguration() *Configuration {
  file, _ := os.Open("config.json")
  decoder := json.NewDecoder(file)
  configuration := &Configuration{}
  decoder.Decode(&configuration)
  fmt.Println(configuration)
  return configuration;
}

func main() {
  var config *Configuration;
  config = loadConfiguration();
  fmt.Printf("%s is domain", config.Port);
  fmt.Printf("Domain: %s", config.Domain);
  m := martini.Classic()

  f := []template.FuncMap{
      template.FuncMap{
        "eq": func(a, b string) bool {
          return a == b
        },
      },
      template.FuncMap{
        "ne": func(a, b string) bool {
          return a != b
        },
      },
  }

  //m.Use(render.Renderer())
  m.Use(render.Renderer(render.Options{
    Directory: "templates", // Specify what path to load the templates from.
    Layout: "layout", // Specify a layout template. Layouts can call {{ yield }} to render the current template.
    Extensions: []string{".tmpl", ".html"}, // Specify extensions to load for templates.
    //Funcs: []template.FuncMap{AppHelpers}, // Specify helper function maps for templates to access.
    //Delims: render.Delims{"{[{", "}]}"}, // Sets delimiters to the specified strings.
    Charset: "UTF-8", // Sets encoding for json and html content-types.
    Funcs: f,
  }))

  store := sessions.NewCookieStore([]byte(config.CookieSecret))
  m.Use(sessions.Sessions("my_session", store))

  m.Get("/", func(r render.Render, session sessions.Session) {
    type Site struct {
      Domain string
      VisitCount  uint
      Env string
      BookmarkletURL string
    }
    BookmarkletURL := "//" + config.Domain + "/javascripts/main.js"
    if config.Env == PROD {
      BookmarkletURL = "//" + config.Domain + "/javascripts/main.js"
    }
    site := Site{config.Domain, 12, config.Env, BookmarkletURL}
    rand := rand.New(rand.NewSource(99))
    csrf := fmt.Sprintf("%f", rand.Float64()*1000000)
    session.Set("CSRF", csrf)
    var msg string;
    if nil != session.Get("FlashMessage") {
      msg = session.Get("FlashMessage").(string)
      session.Delete("FlashMessage")
    } else {
      msg = ""
    }

    r.HTML(200, "hello", struct{A,B, CSRF, FlashMessage string; Site Site}{ "Guesis", "bar", csrf, msg, site })
    //return "
Hello, world!
"
  })

  m.Get("/download", func (r render.Render, session sessions.Session) {

  })

  m.Post("/support", func (res http.ResponseWriter, req *http.Request, params martini.Params, session sessions.Session) {
    var config *Configuration
    config = loadConfiguration()
    mg_client := mailgun.NewClient(config.MG_API_KEY, config.MG_DOMAIN)

    req.ParseForm()
    p := req.Form
    log.Println(req.Form)
    if session.Get("CSRF") == p["csrf"][0] {
      message1 := mailgun.Message{
        FromName: "QSlider",
        FromAddress: "qslide@mg.axcoto.com",
        ToAddress: "kureikain@gmail.com",
        Subject: "Ticket on qslide.axcoto.com",
        Body: "Contact from: " + p["youremail"][0] + " with content: \n
" + p["content"][0],
      }

      fmt.Println("Attempting to send to ", mg_client.Endpoint(message1))

      body, err := mg_client.Send(message1)
      if err != nil {
        fmt.Println("Got an error:", err)
      } else {
        fmt.Println(body)
        session.Set("FlashMessage", "Message sent")
        http.Redirect(res, req, "/", 302)
        //http.Redirect(res, req, "http://slide.dev", http.StatusTemporaryRedirect)
      }
    }
  })

  m.Get("/tutorial", func (r render.Render) {
  })

  //m.Run()
  cmd := exec.Command("pwd","> /tmp/101")
  //cmd := exec.Command("", "5")
  err := cmd.Start()
  if err != nil {
    log.Fatal(err)
  }
  log.Printf("Waiting for command to finish...")
  err = cmd.Wait()
  http.ListenAndServe(fmt.Sprintf(":%s", config.Port), m)
  //http.ListenAndServe(":10005", m)
}
<commit_msg>router<commit_after>package main

import (
  "fmt"
  "net/http"
  "github.com/codegangsta/martini"
  "github.com/codegangsta/martini-contrib/render"
  "github.com/codegangsta/martini-contrib/sessions"
  "os"
  "os/exec"
  "encoding/json"
  "github.com/sirsean/go-mailgun/mailgun"
  "math/rand"
  "log"
  "html/template"
)
const (
  PROD = "Production"
  VERSION = "1.4.1"
)
type Configuration struct
{
  Env string;
  Domain string;
  Port string;
  MG_API_KEY string;
  MG_DOMAIN string;
  CookieSecret string;
}

func loadConfiguration() *Configuration {
  file, _ := os.Open("config.json")
  decoder := json.NewDecoder(file)
  configuration := &Configuration{}
  decoder.Decode(&configuration)
  fmt.Println(configuration)
  return configuration;
}

func main() {
  var config *Configuration;
  config = loadConfiguration();
  fmt.Printf("%s is domain", config.Port);
  fmt.Printf("Domain: %s", config.Domain);
  m := martini.Classic()

  f := []template.FuncMap{
      template.FuncMap{
        "eq": func(a, b string) bool {
          return a == b
        },
      },
      template.FuncMap{
        "ne": func(a, b string) bool {
          return a != b
        },
      },
  }

  //m.Use(render.Renderer())
  m.Use(render.Renderer(render.Options{
    Directory: "templates", // Specify what path to load the templates from.
    Layout: "layout", // Specify a layout template. Layouts can call {{ yield }} to render the current template.
    Extensions: []string{".tmpl", ".html"}, // Specify extensions to load for templates.
    //Funcs: []template.FuncMap{AppHelpers}, // Specify helper function maps for templates to access.
    //Delims: render.Delims{"{[{", "}]}"}, // Sets delimiters to the specified strings.
    Charset: "UTF-8", // Sets encoding for json and html content-types.
    Funcs: f,
  }))

  store := sessions.NewCookieStore([]byte(config.CookieSecret))
  m.Use(sessions.Sessions("my_session", store))

  m.Get("/", func(r render.Render, session sessions.Session) {
    type Site struct {
      Domain string
      VisitCount  uint
      Env string
      BookmarkletURL string
    }
    BookmarkletURL := "//" + config.Domain + "/javascripts/main.js"
    if config.Env == PROD {
      BookmarkletURL = "//" + config.Domain + "/javascripts/main.js"
    }
    site := Site{config.Domain, 12, config.Env, BookmarkletURL}
    rand := rand.New(rand.NewSource(99))
    csrf := fmt.Sprintf("%f", rand.Float64()*1000000)
    session.Set("CSRF", csrf)
    var msg string;
    if nil != session.Get("FlashMessage") {
      msg = session.Get("FlashMessage").(string)
      session.Delete("FlashMessage")
    } else {
      msg = ""
    }

    r.HTML(200, "hello", struct{A,B, CSRF, FlashMessage string; Site Site}{ "Guesis", "bar", csrf, msg, site })
    //return "
Hello, world!
"
  })

  m.Get("/qslider/download", func (r render.Render, session sessions.Session) {

  })

  m.Post("/qslider/support", func (res http.ResponseWriter, req *http.Request, params martini.Params, session sessions.Session) {
    var config *Configuration
    config = loadConfiguration()
    mg_client := mailgun.NewClient(config.MG_API_KEY, config.MG_DOMAIN)

    req.ParseForm()
    p := req.Form
    log.Println(req.Form)
    if session.Get("CSRF") == p["csrf"][0] {
      message1 := mailgun.Message{
        FromName: "QSlider",
        FromAddress: "qslide@mg.axcoto.com",
        ToAddress: "kureikain@gmail.com",
        Subject: "Ticket on qslide.axcoto.com",
        Body: "Contact from: " + p["youremail"][0] + " with content: \n
" + p["content"][0],
      }

      fmt.Println("Attempting to send to ", mg_client.Endpoint(message1))

      body, err := mg_client.Send(message1)
      if err != nil {
        fmt.Println("Got an error:", err)
      } else {
        fmt.Println(body)
        session.Set("FlashMessage", "Message sent")
        http.Redirect(res, req, "/", 302)
        //http.Redirect(res, req, "http://slide.dev", http.StatusTemporaryRedirect)
      }
    }
  })

  m.Get("/qslider/tutorial", func (r render.Render) {
  })

  //m.Run()
  cmd := exec.Command("pwd","> /tmp/101")
  //cmd := exec.Command("", "5")
  err := cmd.Start()
  if err != nil {
    log.Fatal(err)
  }
  log.Printf("Waiting for command to finish...")
  err = cmd.Wait()
  http.ListenAndServe(fmt.Sprintf(":%s", config.Port), m)
  //http.ListenAndServe(":10005", m)
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"errors"
	"fmt"
	"log"
	"math/rand"
	"net"
	"os"
	"strings"
	"time"
)

const framesPerSecond = 8
const getReadyPause = 400
const maxNameLength = 25
const maxParallelRounds = 100
const maxPlayersPerRound = 5
const minPlayersPerRound = 1
const maxRoundWaitingTimeSec = 5
const maxRoundRunningTimeSec = 600
const maxSpeed = 5

const bonusPoint = 5
const lowFactor = 50
const highFactor = 5

const mapWidth = 179
const mapHeight = 38
const nameTableWidth = 30
const horizontalCarWidth = 7
const horizontalCarHeight = 3
const verticalCarWidth = 5
const verticalCarHeight = 3

const colorPrefix = "\x1b["
const colorPostfix = "m"
const bonus = "\xE2\x99\xA5"
const bomb = "\xE2\x9C\xB3"

// States of the round
const (
	COMPILING = 1 + iota
	WAITING
	STARTING
	RUNNING
	FINISHED
)

// Directions
const (
	LEFT = 0 + iota
	RIGHT
	UP
	DOWN
)

// Car Borders
const (
	LEFTUP = 0 + iota
	RIGHTUP
	RIGHTDOWN
	LEFTDOWN
)

// Damage points
const (
	DAMAGE_BACK  = 2
	DAMAGE_FRONT = 4
	DAMAGE_SIDE  = 6
)

// Colors
const (
	RESET   = 0
	BOLD    = 1
	RED     = 31
	GREEN   = 32
	YELLOW  = 33
	BLUE    = 34
	MAGENTA = 35
)

var cars = [4][]byte{}

// http://www.isthe.com/chongo/tech/comp/ansi_escapes.html
var home = []byte{27, 91, 72}
var clear = []byte{27, 91, 50, 74}

//
var middle = []byte{27, 91, 49, 52, 65, 27, 91, 57, 52, 68}

type Config struct {
	Log      *log.Logger
	AcidPath string
}

type Point struct {
	X, Y int
}

type Symbol struct {
	Color int
	Char  []byte
}

type Symbols []Symbol

func getAcid(conf *Config, fileName string) ([]byte, error) {
	fileStat, err := os.Stat(conf.AcidPath + "/" + fileName)
	if err != nil {
		conf.Log.Printf("Acid %s does not exist: %v\n", fileName, err)
		return []byte{}, err
	}

	acid := make([]byte, fileStat.Size())
	f, err := os.OpenFile(conf.AcidPath+"/"+fileName, os.O_RDONLY, os.ModePerm)
	if err != nil {
		conf.Log.Printf("Error while opening %s: %v\n", fileName, err)
		os.Exit(1)
	}
	defer f.Close()

	f.Read(acid)

	return acid, nil
}

func getPlayerData(conn net.Conn, splash []byte) (Player, error) {
	// Get data of player and return the structure
	conn.Write(clear)
	conn.Write(home)
	conn.Write(splash)
	conn.Write(middle)

	io := bufio.NewReader(conn)

	line, _ := io.ReadString('\n')
	name := strings.Replace(strings.Replace(line, "\n", "", -1), "\r", "", -1)
	if name == "" {
		return Player{}, errors.New("Empty name")
	}
	if len(name) > maxNameLength {
		return Player{}, errors.New("Too long name")
	}

	return Player{Conn: conn, BotReady: true, Name: name, Health: 100, Car: Car{Speed: 1}}, nil
}

func checkRoundReady(compileRoundChannel, runningRoundChannel chan Round) {
	fmt.Println("compile/waiting rounds:", len(compileRoundChannel))
	for r := range compileRoundChannel {
		botReady := 0
		fmt.Println("players in round:", len(r.Players))
		for _, player := range r.Players {
			if player.BotReady {
				botReady++
			}
		}

		if len(r.Players) == maxPlayersPerRound ||
			(r.State == WAITING && r.LastStateChange.Add(maxRoundWaitingTimeSec*time.Second).Before(time.Now())) {
			// We are starting round if it is fully booked or waiting time is expired
			fmt.Println("Round has changed to the state STARTING")
			r.State = STARTING
			r.LastStateChange = time.Now()
			runningRoundChannel <- r
		} else if botReady == len(r.Players) && len(r.Players) >= minPlayersPerRound {
			if r.State == COMPILING {
				fmt.Println("Round has changed to the state WAITING")
				r.State = WAITING
				r.LastStateChange = time.Now()
			} else if r.State == WAITING {
				r.writeToAllPlayers([]byte(fmt.Sprintf(
					"Waiting %d seconds for other players to join\n",
					r.LastStateChange.Unix()+maxRoundWaitingTimeSec-time.Now().Unix())), true)
			}
			compileRoundChannel <- r
		} else {
			// Return round back
			compileRoundChannel <- r
		}
		time.Sleep(1 * time.Second)
	}
}

func checkRoundRun(runningRoundChannel chan Round) {
	for {
		for round := range runningRoundChannel {
			for len(round.Players) < maxPlayersPerRound {
				p := round.generateBot()
				p.initPlayer(len(round.Players))
				round.Players = append(round.Players, p)
			}
			go round.start()
		}
	}
}

func (symbols Symbols) symbolsToByte() []byte {
	var returnSlice []byte
	for _, symbol := range symbols {
		// Should be something like \x1b[31m^\x1b[0m for symbols with colors or ^ without
		if symbol.Color != RESET {
			returnSlice = append(returnSlice, []byte(colorPrefix+fmt.Sprintf("%d", symbol.Color)+colorPostfix)...)
		}
		returnSlice = append(returnSlice, symbol.Char...)
		if symbol.Color != RESET {
			returnSlice = append(returnSlice, []byte(colorPrefix+fmt.Sprintf("%d", RESET)+colorPostfix)...)
		}
	}
	return returnSlice
}

func prepareRound(conn net.Conn, splash []byte, compileRoundChannel, runningRoundChannel chan Round) {
	// Check for name and stuff. Ask if he agrees to play with bots
	p, err := getPlayerData(conn, splash)
	if err != nil {
		conn.Close()
		return
	}

	if len(compileRoundChannel) == 0 {
		r := Round{State: COMPILING, FrameBuffer: make([]Symbol, mapWidth*mapHeight), Bonus: Point{-1, -1}, Bombs: make(map[Point]bool)}
		compileRoundChannel <- r
	}

	p.checkBestRoundForPlayer(compileRoundChannel)
}

func main() {
	// Make random unique
	rand.Seed(time.Now().Unix())

	logfile, err := os.OpenFile("/var/log/crashci.log", os.O_RDWR|os.O_CREATE|os.O_APPEND, 0600)
	conf := &Config{log.New(logfile, "", log.Ldate|log.Lmicroseconds|log.Lshortfile), "/Users/leoleovich/go/src/github.com/leoleovich/crashci/artifacts"}
	l, err := net.Listen("tcp", ":4242")
	if err != nil {
		os.Exit(2)
	}
	defer l.Close()

	// Read sketches
	cars[LEFT], _ = getAcid(conf, "carLeft.txt")
	cars[RIGHT], _ = getAcid(conf, "carRight.txt")
	cars[UP], _ = getAcid(conf, "carUp.txt")
	cars[DOWN], _ = getAcid(conf, "carDown.txt")
	splash, _ := getAcid(conf, "splash.txt")

	compileRoundChannel := make(chan Round, maxParallelRounds)
	runningRoundChannel := make(chan Round, maxParallelRounds)

	go checkRoundReady(compileRoundChannel, runningRoundChannel)
	go checkRoundRun(runningRoundChannel)

	for {
		conn, err := l.Accept()
		if err != nil {
			conf.Log.Println("Failed to accept request", err)
		}

		go prepareRound(conn, splash, compileRoundChannel, runningRoundChannel)

	}
}
<commit_msg>Parse flags<commit_after>package main

import (
	"bufio"
	"errors"
	"flag"
	"fmt"
	"log"
	"math/rand"
	"net"
	"os"
	"strings"
	"time"
)

const framesPerSecond = 8
const getReadyPause = 400
const maxNameLength = 25
const maxParallelRounds = 100
const maxPlayersPerRound = 5
const minPlayersPerRound = 1
const maxRoundWaitingTimeSec = 5
const maxRoundRunningTimeSec = 600
const maxSpeed = 5

const bonusPoint = 5
const lowFactor = 50
const highFactor = 5

const mapWidth = 179
const mapHeight = 38
const nameTableWidth = 30
const horizontalCarWidth = 7
const horizontalCarHeight = 3
const verticalCarWidth = 5
const verticalCarHeight = 3

const colorPrefix = "\x1b["
const colorPostfix = "m"
const bonus = "\xE2\x99\xA5"
const bomb = "\xE2\x9C\xB3"

// States of the round
const (
	COMPILING = 1 + iota
	WAITING
	STARTING
	RUNNING
	FINISHED
)

// Directions
const (
	LEFT = 0 + iota
	RIGHT
	UP
	DOWN
)

// Car Borders
const (
	LEFTUP = 0 + iota
	RIGHTUP
	RIGHTDOWN
	LEFTDOWN
)

// Damage points
const (
	DAMAGE_BACK  = 2
	DAMAGE_FRONT = 4
	DAMAGE_SIDE  = 6
)

// Colors
const (
	RESET   = 0
	BOLD    = 1
	RED     = 31
	GREEN   = 32
	YELLOW  = 33
	BLUE    = 34
	MAGENTA = 35
)

var cars = [4][]byte{}

// http://www.isthe.com/chongo/tech/comp/ansi_escapes.html
var home = []byte{27, 91, 72}
var clear = []byte{27, 91, 50, 74}

//
var middle = []byte{27, 91, 49, 52, 65, 27, 91, 57, 52, 68}
var conf Config

type Config struct {
	Log      *log.Logger
	AcidPath string
}

type Point struct {
	X, Y int
}

type Symbol struct {
	Color int
	Char  []byte
}

type Symbols []Symbol

func getAcid(fileName string) ([]byte, error) {
	fileStat, err := os.Stat(conf.AcidPath + "/" + fileName)
	if err != nil {
		conf.Log.Printf("Acid %s does not exist: %v\n", fileName, err)
		return []byte{}, err
	}

	acid := make([]byte, fileStat.Size())
	f, err := os.OpenFile(conf.AcidPath+"/"+fileName, os.O_RDONLY, os.ModePerm)
	if err != nil {
		conf.Log.Printf("Error while opening %s: %v\n", fileName, err)
		os.Exit(1)
	}
	defer f.Close()

	f.Read(acid)

	return acid, nil
}

func getPlayerData(conn net.Conn, splash []byte) (Player, error) {
	// Get data of player and return the structure
	conn.Write(clear)
	conn.Write(home)
	conn.Write(splash)
	conn.Write(middle)

	io := bufio.NewReader(conn)

	line, _ := io.ReadString('\n')
	name := strings.Replace(strings.Replace(line, "\n", "", -1), "\r", "", -1)
	if name == "" {
		return Player{}, errors.New("Empty name")
	}
	if len(name) > maxNameLength {
		return Player{}, errors.New("Too long name")
	}

	return Player{Conn: conn, BotReady: true, Name: name, Health: 100, Car: Car{Speed: 1}}, nil
}

func checkRoundReady(compileRoundChannel, runningRoundChannel chan Round) {
	fmt.Println("compile/waiting rounds:", len(compileRoundChannel))
	for r := range compileRoundChannel {
		botReady := 0
		fmt.Println("players in round:", len(r.Players))
		for _, player := range r.Players {
			if player.BotReady {
				botReady++
			}
		}

		if len(r.Players) == maxPlayersPerRound ||
			(r.State == WAITING && r.LastStateChange.Add(maxRoundWaitingTimeSec*time.Second).Before(time.Now())) {
			// We are starting round if it is fully booked or waiting time is expired
			fmt.Println("Round has changed to the state STARTING")
			r.State = STARTING
			r.LastStateChange = time.Now()
			runningRoundChannel <- r
		} else if botReady == len(r.Players) && len(r.Players) >= minPlayersPerRound {
			if r.State == COMPILING {
				fmt.Println("Round has changed to the state WAITING")
				r.State = WAITING
				r.LastStateChange = time.Now()
			} else if r.State == WAITING {
				r.writeToAllPlayers([]byte(fmt.Sprintf(
					"Waiting %d seconds for other players to join\n",
					r.LastStateChange.Unix()+maxRoundWaitingTimeSec-time.Now().Unix())), true)
			}
			compileRoundChannel <- r
		} else {
			// Return round back
			compileRoundChannel <- r
		}
		time.Sleep(1 * time.Second)
	}
}

func checkRoundRun(runningRoundChannel chan Round) {
	for {
		for round := range runningRoundChannel {
			for len(round.Players) < maxPlayersPerRound {
				p := round.generateBot()
				p.initPlayer(len(round.Players))
				round.Players = append(round.Players, p)
			}
			go round.start()
		}
	}
}

func (symbols Symbols) symbolsToByte() []byte {
	var returnSlice []byte
	for _, symbol := range symbols {
		// Should be something like \x1b[31m^\x1b[0m for symbols with colors or ^ without
		if symbol.Color != RESET {
			returnSlice = append(returnSlice, []byte(colorPrefix+fmt.Sprintf("%d", symbol.Color)+colorPostfix)...)
		}
		returnSlice = append(returnSlice, symbol.Char...)
		if symbol.Color != RESET {
			returnSlice = append(returnSlice, []byte(colorPrefix+fmt.Sprintf("%d", RESET)+colorPostfix)...)
		}
	}
	return returnSlice
}

func prepareRound(conn net.Conn, splash []byte, compileRoundChannel, runningRoundChannel chan Round) {
	// Check for name and stuff. Ask if he agrees to play with bots
	p, err := getPlayerData(conn, splash)
	if err != nil {
		conn.Close()
		return
	}

	if len(compileRoundChannel) == 0 {
		r := Round{State: COMPILING, FrameBuffer: make([]Symbol, mapWidth*mapHeight), Bonus: Point{-1, -1}, Bombs: make(map[Point]bool)}
		compileRoundChannel <- r
	}

	p.checkBestRoundForPlayer(compileRoundChannel)
}

func main() {
	// Make random unique
	rand.Seed(time.Now().Unix())
	var logFile string

	flag.StringVar(&logFile, "l", "/var/log/race.log", "Log file")
	flag.StringVar(&conf.AcidPath, "a", "/Users/leoleovich/go/src/github.com/leoleovich/crashci/artifacts", "Artifacts location")
	flag.Parse()

	logfile, err := os.OpenFile("/var/log/crashci.log", os.O_RDWR|os.O_CREATE|os.O_APPEND, 0600)
	conf = Config{log.New(logfile, "", log.Ldate|log.Lmicroseconds|log.Lshortfile), "/Users/leoleovich/go/src/github.com/leoleovich/crashci/artifacts"}

	l, err := net.Listen("tcp", ":4242")
	if err != nil {
		os.Exit(2)
	}
	defer l.Close()

	// Read sketches
	cars[LEFT], _ = getAcid("carLeft.txt")
	cars[RIGHT], _ = getAcid("carRight.txt")
	cars[UP], _ = getAcid("carUp.txt")
	cars[DOWN], _ = getAcid("carDown.txt")
	splash, _ := getAcid("splash.txt")

	compileRoundChannel := make(chan Round, maxParallelRounds)
	runningRoundChannel := make(chan Round, maxParallelRounds)

	go checkRoundReady(compileRoundChannel, runningRoundChannel)
	go checkRoundRun(runningRoundChannel)

	for {
		conn, err := l.Accept()
		if err != nil {
			conf.Log.Println("Failed to accept request", err)
		}

		go prepareRound(conn, splash, compileRoundChannel, runningRoundChannel)

	}
}
<|endoftext|>


<commit_before>package chuper

import (
	"fmt"
	"net/http"
	"time"

	"github.com/PuerkitoBio/goquery"
	"github.com/oli-g/fetchbot"
)

const (
	DefaultCrawlDelay      = 5 * time.Second
	DefaultCrawlPoliteness = false
)

var (
	DefaultHTTPClient = http.DefaultClient

	DefaultCache = NewMemoryCache()

	DefaultErrorHandler = fetchbot.HandlerFunc(func(ctx *fetchbot.Context, res *http.Response, err error) {
		fmt.Printf("chuper - %s - error: %s %s - %s\n", time.Now().Format(time.RFC3339), ctx.Cmd.Method(), ctx.Cmd.URL(), err)
	})

	DefaultLogHandlerFunc = func(ctx *fetchbot.Context, res *http.Response, err error) {
		if err == nil {
			fmt.Printf("chuper - %s - info: [%d] %s %s - %s\n", time.Now().Format(time.RFC3339), res.StatusCode, ctx.Cmd.Method(), ctx.Cmd.URL(), res.Header.Get("Content-Type"))
		}
	}
)

type Crawler struct {
	CrawlDelay      time.Duration
	CrawlPoliteness bool
	HTTPClient      fetchbot.Doer
	Cache           Cache
	ErrorHandler    fetchbot.Handler
	LogHandlerFunc  func(ctx *fetchbot.Context, res *http.Response, err error)

	mux *fetchbot.Mux
	f   *fetchbot.Fetcher
	q   *fetchbot.Queue
}

// New returns an initialized Crawler.
func New() *Crawler {
	return &Crawler{
		CrawlDelay:      DefaultCrawlDelay,
		CrawlPoliteness: DefaultCrawlPoliteness,
		HTTPClient:      DefaultHTTPClient,
		Cache:           DefaultCache,
		ErrorHandler:    DefaultErrorHandler,
		LogHandlerFunc:  DefaultLogHandlerFunc,
		mux:             fetchbot.NewMux(),
	}
}

func (c *Crawler) Start() *fetchbot.Queue {
	c.mux.HandleErrors(c.ErrorHandler)
	l := newLogHandler(c.mux, c.LogHandlerFunc)

	f := fetchbot.New(l)
	f.CrawlDelay = c.CrawlDelay
	f.CrawlPoliteness = c.CrawlPoliteness
	f.HttpClient = c.HTTPClient

	c.f = f
	c.q = c.f.Start()

	return c.q
}

func (c *Crawler) Block() {
	c.q.Block()
}

func (c *Crawler) Enqueue(method string, rawurl ...string) error {
	for _, u := range rawurl {
		ok := true
		if c.mustCache() {
			ok, _ = c.Cache.SetNX(u, true)
		}
		if ok {
			if _, err := c.q.SendString(method, u); err != nil {
				return err
			}
		}
	}
	return nil
}

type ResponseCriteria struct {
	Method      string
	ContentType string
	Status      int
	MinStatus   int
	MaxStatus   int
	Path        string
	Host        string
}

func (c *Crawler) Match(r *ResponseCriteria) *fetchbot.ResponseMatcher {
	m := c.mux.Response()

	if r.Method != "" {
		m.Method(r.Method)
	}

	if r.ContentType != "" {
		m.ContentType(r.ContentType)
	}

	if r.Status != 0 {
		m.Status(r.Status)
	} else {
		if r.MinStatus != 0 && r.MaxStatus != 0 {
			m.StatusRange(r.MinStatus, r.MaxStatus)
		} else {
			if r.MinStatus != 0 {
				m.Status(r.MinStatus)
			}
			if r.MaxStatus != 0 {
				m.Status(r.MaxStatus)
			}
		}
	}

	if r.Path != "" {
		m.Path(r.Path)
	}

	if r.Host != "" {
		m.Host(r.Host)
	}

	return m
}

func (c *Crawler) Register(rc *ResponseCriteria, procs ...Processor) {
	m := c.Match(rc)
	h := newDocHandler(c.Cache, procs...)
	m.Handler(h)
}

func (c *Crawler) mustCache() bool {
	if c.Cache == nil {
		return false
	}
	return true
}

func newLogHandler(wrapped fetchbot.Handler, f func(ctx *fetchbot.Context, res *http.Response, err error)) fetchbot.Handler {
	return fetchbot.HandlerFunc(func(ctx *fetchbot.Context, res *http.Response, err error) {
		f(ctx, res, err)
		wrapped.Handle(ctx, res, err)
	})
}

func newDocHandler(cache Cache, procs ...Processor) fetchbot.Handler {
	return fetchbot.HandlerFunc(func(ctx *fetchbot.Context, res *http.Response, err error) {
		context := &Context{ctx, cache}
		doc, err := goquery.NewDocumentFromResponse(res)
		if err != nil {
			fmt.Printf("chuper - %s - error: %s %s - %s\n", time.Now().Format(time.RFC3339), ctx.Cmd.Method(), ctx.Cmd.URL(), err)
			return
		}
		for _, p := range procs {
			err = p.Process(context, doc)
			if err != nil {
				fmt.Printf("chuper - %s - error: %s %s - %s\n", time.Now().Format(time.RFC3339), ctx.Cmd.Method(), ctx.Cmd.URL(), err)
				return
			}
		}
	})
}
<commit_msg>Add EnqueueWithSource method to Crawler<commit_after>package chuper

import (
	"fmt"
	"net/http"
	"net/url"
	"time"

	"github.com/PuerkitoBio/goquery"
	"github.com/oli-g/fetchbot"
)

const (
	DefaultCrawlDelay      = 5 * time.Second
	DefaultCrawlPoliteness = false
)

var (
	DefaultHTTPClient = http.DefaultClient

	DefaultCache = NewMemoryCache()

	DefaultErrorHandler = fetchbot.HandlerFunc(func(ctx *fetchbot.Context, res *http.Response, err error) {
		fmt.Printf("chuper - %s - error: %s %s - %s\n", time.Now().Format(time.RFC3339), ctx.Cmd.Method(), ctx.Cmd.URL(), err)
	})

	DefaultLogHandlerFunc = func(ctx *fetchbot.Context, res *http.Response, err error) {
		if err == nil {
			fmt.Printf("chuper - %s - info: [%d] %s %s - %s\n", time.Now().Format(time.RFC3339), res.StatusCode, ctx.Cmd.Method(), ctx.Cmd.URL(), res.Header.Get("Content-Type"))
		}
	}
)

type Crawler struct {
	CrawlDelay      time.Duration
	CrawlPoliteness bool
	HTTPClient      fetchbot.Doer
	Cache           Cache
	ErrorHandler    fetchbot.Handler
	LogHandlerFunc  func(ctx *fetchbot.Context, res *http.Response, err error)

	mux *fetchbot.Mux
	f   *fetchbot.Fetcher
	q   *fetchbot.Queue
}

// New returns an initialized Crawler.
func New() *Crawler {
	return &Crawler{
		CrawlDelay:      DefaultCrawlDelay,
		CrawlPoliteness: DefaultCrawlPoliteness,
		HTTPClient:      DefaultHTTPClient,
		Cache:           DefaultCache,
		ErrorHandler:    DefaultErrorHandler,
		LogHandlerFunc:  DefaultLogHandlerFunc,
		mux:             fetchbot.NewMux(),
	}
}

func (c *Crawler) Start() *fetchbot.Queue {
	c.mux.HandleErrors(c.ErrorHandler)
	l := newLogHandler(c.mux, c.LogHandlerFunc)

	f := fetchbot.New(l)
	f.CrawlDelay = c.CrawlDelay
	f.CrawlPoliteness = c.CrawlPoliteness
	f.HttpClient = c.HTTPClient

	c.f = f
	c.q = c.f.Start()

	return c.q
}

func (c *Crawler) Block() {
	c.q.Block()
}

func (c *Crawler) Enqueue(method string, rawURL ...string) error {
	for _, u := range rawURL {
		ok := true
		if c.mustCache() {
			ok, _ = c.Cache.SetNX(u, true)
		}
		if ok {
			if _, err := c.q.SendString(method, u); err != nil {
				return err
			}
		}
	}
	return nil
}

func (c *Crawler) EnqueueWithSource(method string, URL string, sourceURL string) (bool, error) {
	ok := true
	if c.mustCache() {
		ok, _ = c.Cache.SetNX(URL, true)
	}
	if ok {
		u, err := url.Parse(URL)
		if err != nil {
			return ok, err
		}
		s, err := url.Parse(sourceURL)
		if err != nil {
			return ok, err
		}
		cmd := NewCmd(u, method, s)
		err = c.q.Send(cmd)
		return ok, err
	}
	return ok, nil
}

type ResponseCriteria struct {
	Method      string
	ContentType string
	Status      int
	MinStatus   int
	MaxStatus   int
	Path        string
	Host        string
}

func (c *Crawler) Match(r *ResponseCriteria) *fetchbot.ResponseMatcher {
	m := c.mux.Response()

	if r.Method != "" {
		m.Method(r.Method)
	}

	if r.ContentType != "" {
		m.ContentType(r.ContentType)
	}

	if r.Status != 0 {
		m.Status(r.Status)
	} else {
		if r.MinStatus != 0 && r.MaxStatus != 0 {
			m.StatusRange(r.MinStatus, r.MaxStatus)
		} else {
			if r.MinStatus != 0 {
				m.Status(r.MinStatus)
			}
			if r.MaxStatus != 0 {
				m.Status(r.MaxStatus)
			}
		}
	}

	if r.Path != "" {
		m.Path(r.Path)
	}

	if r.Host != "" {
		m.Host(r.Host)
	}

	return m
}

func (c *Crawler) Register(rc *ResponseCriteria, procs ...Processor) {
	m := c.Match(rc)
	h := newDocHandler(c.Cache, procs...)
	m.Handler(h)
}

func (c *Crawler) mustCache() bool {
	if c.Cache == nil {
		return false
	}
	return true
}

func newLogHandler(wrapped fetchbot.Handler, f func(ctx *fetchbot.Context, res *http.Response, err error)) fetchbot.Handler {
	return fetchbot.HandlerFunc(func(ctx *fetchbot.Context, res *http.Response, err error) {
		f(ctx, res, err)
		wrapped.Handle(ctx, res, err)
	})
}

func newDocHandler(cache Cache, procs ...Processor) fetchbot.Handler {
	return fetchbot.HandlerFunc(func(ctx *fetchbot.Context, res *http.Response, err error) {
		context := &Context{ctx, cache}
		doc, err := goquery.NewDocumentFromResponse(res)
		if err != nil {
			fmt.Printf("chuper - %s - error: %s %s - %s\n", time.Now().Format(time.RFC3339), ctx.Cmd.Method(), ctx.Cmd.URL(), err)
			return
		}
		for _, p := range procs {
			err = p.Process(context, doc)
			if err != nil {
				fmt.Printf("chuper - %s - error: %s %s - %s\n", time.Now().Format(time.RFC3339), ctx.Cmd.Method(), ctx.Cmd.URL(), err)
				return
			}
		}
	})
}
<|endoftext|>