<commit_before>package orm

import (
	"database/sql"
	"errors"
	"fmt"
	"log"
	"reflect"
	"strings"
)

var dbHive map[string]*sql.DB = make(map[string]*sql.DB)

//create new database
func NewDatabase(dbname, dbtype, url string) {
	db, err := sql.Open(dbtype, url)
	if err != nil {
		panic(err.Error())
	}
	err = db.Ping()
	if err != nil {
		panic(err.Error())
	}
	dbHive[dbname] = db
}

//module
type Module struct {
	columnstr string //select field
	tableName string //table
	filters   string //condition
	orderby   string //orderby
	limit     string //limit
	join      string //join
	pk        string //pk
	dbname    string //dbname
}

//create new Module
func NewModule(tableName string) *Module {
	m := &Module{tableName: tableName, columnstr: "*", dbname: "default", pk: "id"}
	return m
}

func (m *Module) Clean() *Module {
	m.columnstr = "*"
	m.filters = ""
	m.orderby = ""
	m.limit = ""
	m.join = ""
	m.pk = "id"
	return m
}

func (m *Module) GetDB() *sql.DB {
	return dbHive[m.dbname]
}

//change db
func (m *Module) User(dbname string) *Module {
	m.dbname = dbname
	return m
}

//select fields
func (m *Module) Select(fields ...string) *Module {
	m.columnstr = ""
	for _, f := range fields {
		m.columnstr = m.columnstr + f + ","
	}
	return m
}

//Filter
func (m *Module) Filter(param ...interface{}) *Module {
	for _, p := range param {
		m.filters += fmt.Sprintf("%v", p)
	}
	return m
}

//orderBy
func (m *Module) OrderBy(param string) *Module {
	m.orderby = fmt.Sprintf("ORDER By %v", param)
	return m
}

//limit
func (m *Module) Limit(size ...int) *Module {
	if len(size) > 1 {
		m.limit = fmt.Sprintf("Limit %d,%d", size[0], size[1])
		return m
	} else {
		m.limit = fmt.Sprintf("Limit %d", size[0])
		return m
	}
}

//leftJoin
func (m *Module) LeftJoin(table, condition string) *Module {
	m.join = fmt.Sprintf("LEFT JOIN %v ON %v", table, condition)
	return m
}

//rightJoin
func (m *Module) RightJoin(table, condition string) *Module {
	m.join = fmt.Sprintf("RIGHT JOIN %v ON %v", table, condition)
	return m
}

//join
func (m *Module) Join(table, condition string) *Module {
	m.join = fmt.Sprintf("INNER JOIN %v ON %v", table, condition)
	return m
}

//fulljoin
func (m *Module) FullJoin(table, condition string) *Module {
	m.join = fmt.Sprintf("FULL JOIN %v ON %v", table, condition)
	return m
}

func (m *Module) getSqlString() string {
	columnstr := m.columnstr
	if l := len(columnstr); l > 1 {
		columnstr = columnstr[:l-1]
	}
	query := m.buildSql(columnstr)
	query += " " + m.limit
	log.Println("sql = ", query)
	return query
}

func (m *Module) buildSql(columnstr string) string {
	where := m.filters
	where = strings.TrimSpace(where)
	if len(where) > 0 {
		where = "where " + where
	}
	query := fmt.Sprintf("select %v from %v %v %v %v", columnstr, m.tableName, m.join, where, m.orderby)
	return query
}

func (m *Module) QueryPage(page *Page, callBackFunc func(*sql.Rows)) error {
	db := dbHive[m.dbname]
	m.Limit(page.StartRow(), page.PageSize)
	query := m.buildSql("count(*)")
	row := db.QueryRow(query)
	err := row.Scan(&page.ResultCount)
	if err != nil {
		return err
	}
	rows, err := db.Query(m.getSqlString())
	if err != nil {
		return err
	}
	defer rows.Close()
	callBackFunc(rows)
	return nil
}

func (m *Module) Query(callBackFunc func(*sql.Rows)) error {
	db := dbHive[m.dbname]
	rows, err := db.Query(m.getSqlString())
	if err != nil {
		return err
	}
	defer rows.Close()
	callBackFunc(rows)
	return nil
}
func (m *Module) QueryOne(callBackFunc func(*sql.Row)) {
	db := dbHive[m.dbname]
	row := db.QueryRow(m.getSqlString())
	callBackFunc(row)
}

func (m *Module) IsExist() (bool, error) {
	count, err := m.Count()
	if count > 0 {
		return true, nil
	}
	return false, err
}

func (m *Module) Count() (int, error) {
	db := dbHive[m.dbname]
	query := m.buildSql("count(*)")
	log.Println("sql = ", query)
	row := db.QueryRow(query)
	var count int
	err := row.Scan(&count)
	return count, err
}

func (m *Module) OneRecord() (record Record, err error) {
	rs, err := m.Limit(1).AllRecords()
	if err != nil {
		return record, err
	}
	if len(rs) == 0 {
		return NewRecord(), errors.New("not fond record")
	}
	return rs[0], nil
}

func (m *Module) AllRecords() ([]Record, error) {
	db := dbHive[m.dbname]
	rows, err := db.Query(m.getSqlString())
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	records := make([]Record, 0)
	columns, _ := rows.Columns()
	values := make([]sql.RawBytes, len(columns))
	scanargs := make([]interface{}, len(values))
	for i := range values {
		scanargs[i] = &values[i]
	}
	for rows.Next() {
		err := rows.Scan(scanargs...)
		if err != nil {
			fmt.Println(err)
		}
		record := NewRecord()
		for i, v := range values {
			record.result[columns[i]] = v
		}
		records = append(records, record)
	}
	return records, nil
}
func (m *Module) SetPK(pk string) *Module {
	m.pk = pk
	return m
}

func (m *Module) FindRecordById(id int) *Module {
	m.Filter(m.pk, "=", id)
	return m
}

func (m *Module) Insert(record Record) (int, error) {
	columns := ""
	values := ""
	for c, v := range record.param {
		columns = columns + c + ","
		rv := reflect.ValueOf(v)
		switch rv.Kind() {
		case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Bool:
			values = values + fmt.Sprintf("%v", v) + ","
		default:
			values = values + fmt.Sprintf("'%v'", v) + ","
		}
	}
	if l := len(columns); l > 0 {
		columns = columns[:l-1]
	}
	if l := len(values); l > 0 {
		values = values[:l-1]
	}
	insertSql := fmt.Sprintf("insert into %v(%v) values(%v)", m.tableName, columns, values)
	fmt.Println(insertSql)
	db := dbHive[m.dbname]
	result, err := db.Exec(insertSql)
	if err != nil {
		return 0, err
	}
	id, err := result.LastInsertId()
	return int(id), err
}

func (m *Module) Update(record Record) error {
	values := ""
	for c, v := range record.param {
		values = values + c + "="
		rv := reflect.ValueOf(v)
		switch rv.Kind() {
		case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Bool:
			values += fmt.Sprintf("%v", v)
		default:
			values += fmt.Sprintf("'%v'", v)
		}
		values += ","
	}
	if l := len(values); l > 0 {
		values = values[:l-1]
	}
	sql := fmt.Sprintf("update %v set %v where %v", m.tableName, values, m.filters)
	log.Println("sql = ", sql)
	db := dbHive[m.dbname]
	_, err := db.Exec(sql)
	return err
}

func (m *Module) DeleteById(id int) error {
	m.Filter(m.pk, "=", id)
	return m.Delete()
}

func (m *Module) FindById(id int) *Module {
	m.Filter(m.pk, "=", id)
	return m
}

func (m *Module) Delete() error {
	where := m.filters
	where = strings.TrimSpace(where)
	if len(where) > 0 {
		where = "where " + where
	}
	delSql := fmt.Sprintf("delete from %v %v", m.tableName, where)
	fmt.Println(delSql)
	_, err := dbHive[m.dbname].Exec(delSql)
	return err
}
<commit_msg>add log<commit_after>package orm

import (
	"database/sql"
	"errors"
	"fmt"
	"log"
	"reflect"
	"strings"
)

var dbHive map[string]*sql.DB = make(map[string]*sql.DB)

//create new database
func NewDatabase(dbname, dbtype, url string) {
	db, err := sql.Open(dbtype, url)
	if err != nil {
		panic(err.Error())
	}
	err = db.Ping()
	if err != nil {
		panic(err.Error())
	}
	dbHive[dbname] = db
}

//module
type Module struct {
	columnstr string //select field
	tableName string //table
	filters   string //condition
	orderby   string //orderby
	limit     string //limit
	join      string //join
	pk        string //pk
	dbname    string //dbname
}

//create new Module
func NewModule(tableName string) *Module {
	m := &Module{tableName: tableName, columnstr: "*", dbname: "default", pk: "id"}
	return m
}

func (m *Module) Clean() *Module {
	m.columnstr = "*"
	m.filters = ""
	m.orderby = ""
	m.limit = ""
	m.join = ""
	m.pk = "id"
	return m
}

func (m *Module) GetDB() *sql.DB {
	return dbHive[m.dbname]
}

//change db
func (m *Module) User(dbname string) *Module {
	m.dbname = dbname
	return m
}

//select fields
func (m *Module) Select(fields ...string) *Module {
	m.columnstr = ""
	for _, f := range fields {
		m.columnstr = m.columnstr + f + ","
	}
	return m
}

//Filter
func (m *Module) Filter(param ...interface{}) *Module {
	for _, p := range param {
		m.filters += fmt.Sprintf("%v", p)
	}
	return m
}

//orderBy
func (m *Module) OrderBy(param string) *Module {
	m.orderby = fmt.Sprintf("ORDER By %v", param)
	return m
}

//limit
func (m *Module) Limit(size ...int) *Module {
	if len(size) > 1 {
		m.limit = fmt.Sprintf("Limit %d,%d", size[0], size[1])
		return m
	} else {
		m.limit = fmt.Sprintf("Limit %d", size[0])
		return m
	}
}

//leftJoin
func (m *Module) LeftJoin(table, condition string) *Module {
	m.join = fmt.Sprintf("LEFT JOIN %v ON %v", table, condition)
	return m
}

//rightJoin
func (m *Module) RightJoin(table, condition string) *Module {
	m.join = fmt.Sprintf("RIGHT JOIN %v ON %v", table, condition)
	return m
}

//join
func (m *Module) Join(table, condition string) *Module {
	m.join = fmt.Sprintf("INNER JOIN %v ON %v", table, condition)
	return m
}

//fulljoin
func (m *Module) FullJoin(table, condition string) *Module {
	m.join = fmt.Sprintf("FULL JOIN %v ON %v", table, condition)
	return m
}

func (m *Module) getSqlString() string {
	columnstr := m.columnstr
	if l := len(columnstr); l > 1 {
		columnstr = columnstr[:l-1]
	}
	query := m.buildSql(columnstr)
	query += " " + m.limit
	log.Println("sql = ", query)
	return query
}

func (m *Module) buildSql(columnstr string) string {
	where := m.filters
	where = strings.TrimSpace(where)
	if len(where) > 0 {
		where = "where " + where
	}
	query := fmt.Sprintf("select %v from %v %v %v %v", columnstr, m.tableName, m.join, where, m.orderby)
	return query
}

func (m *Module) QueryPage(page *Page, callBackFunc func(*sql.Rows)) error {
	db := dbHive[m.dbname]
	m.Limit(page.StartRow(), page.PageSize)
	query := m.buildSql("count(*)")
	log.Println(query)
	row := db.QueryRow(query)
	err := row.Scan(&page.ResultCount)
	if err != nil {
		return err
	}
	rows, err := db.Query(m.getSqlString())
	if err != nil {
		return err
	}
	defer rows.Close()
	callBackFunc(rows)
	return nil
}

func (m *Module) Query(callBackFunc func(*sql.Rows)) error {
	db := dbHive[m.dbname]
	rows, err := db.Query(m.getSqlString())
	if err != nil {
		return err
	}
	defer rows.Close()
	callBackFunc(rows)
	return nil
}
func (m *Module) QueryOne(callBackFunc func(*sql.Row)) {
	db := dbHive[m.dbname]
	row := db.QueryRow(m.getSqlString())
	callBackFunc(row)
}

func (m *Module) IsExist() (bool, error) {
	count, err := m.Count()
	if count > 0 {
		return true, nil
	}
	return false, err
}

func (m *Module) Count() (int, error) {
	db := dbHive[m.dbname]
	query := m.buildSql("count(*)")
	log.Println("sql = ", query)
	row := db.QueryRow(query)
	var count int
	err := row.Scan(&count)
	return count, err
}

func (m *Module) OneRecord() (record Record, err error) {
	rs, err := m.Limit(1).AllRecords()
	if err != nil {
		return record, err
	}
	if len(rs) == 0 {
		return NewRecord(), errors.New("not fond record")
	}
	return rs[0], nil
}

func (m *Module) AllRecords() ([]Record, error) {
	db := dbHive[m.dbname]
	rows, err := db.Query(m.getSqlString())
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	records := make([]Record, 0)
	columns, _ := rows.Columns()
	values := make([]sql.RawBytes, len(columns))
	scanargs := make([]interface{}, len(values))
	for i := range values {
		scanargs[i] = &values[i]
	}
	for rows.Next() {
		err := rows.Scan(scanargs...)
		if err != nil {
			fmt.Println(err)
		}
		record := NewRecord()
		for i, v := range values {
			record.result[columns[i]] = v
		}
		records = append(records, record)
	}
	return records, nil
}
func (m *Module) SetPK(pk string) *Module {
	m.pk = pk
	return m
}

func (m *Module) FindRecordById(id int) *Module {
	m.Filter(m.pk, "=", id)
	return m
}

func (m *Module) Insert(record Record) (int, error) {
	columns := ""
	values := ""
	for c, v := range record.param {
		columns = columns + c + ","
		rv := reflect.ValueOf(v)
		switch rv.Kind() {
		case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Bool:
			values = values + fmt.Sprintf("%v", v) + ","
		default:
			values = values + fmt.Sprintf("'%v'", v) + ","
		}
	}
	if l := len(columns); l > 0 {
		columns = columns[:l-1]
	}
	if l := len(values); l > 0 {
		values = values[:l-1]
	}
	insertSql := fmt.Sprintf("insert into %v(%v) values(%v)", m.tableName, columns, values)
	fmt.Println(insertSql)
	db := dbHive[m.dbname]
	result, err := db.Exec(insertSql)
	if err != nil {
		return 0, err
	}
	id, err := result.LastInsertId()
	return int(id), err
}

func (m *Module) Update(record Record) error {
	values := ""
	for c, v := range record.param {
		values = values + c + "="
		rv := reflect.ValueOf(v)
		switch rv.Kind() {
		case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Bool:
			values += fmt.Sprintf("%v", v)
		default:
			values += fmt.Sprintf("'%v'", v)
		}
		values += ","
	}
	if l := len(values); l > 0 {
		values = values[:l-1]
	}
	sql := fmt.Sprintf("update %v set %v where %v", m.tableName, values, m.filters)
	log.Println("sql = ", sql)
	db := dbHive[m.dbname]
	_, err := db.Exec(sql)
	return err
}

func (m *Module) DeleteById(id int) error {
	m.Filter(m.pk, "=", id)
	return m.Delete()
}

func (m *Module) FindById(id int) *Module {
	m.Filter(m.pk, "=", id)
	return m
}

func (m *Module) Delete() error {
	where := m.filters
	where = strings.TrimSpace(where)
	if len(where) > 0 {
		where = "where " + where
	}
	delSql := fmt.Sprintf("delete from %v %v", m.tableName, where)
	fmt.Println(delSql)
	_, err := dbHive[m.dbname].Exec(delSql)
	return err
}
<|endoftext|>


<commit_before>package osc

// #cgo LDFLAGS: -llo
// #include "lo/lo.h"
import "C"

import (
    "unsafe"
    "runtime"
    )

/* to implement liblo's high level OSC interface, we need the following:
timetag type
message arg type, can act as int32, int64, float, double, char, unsigned char, uint8[4], and timetag
 */

type Timetag struct {
    uint32 Sec
    uint32 Frac
}

type MidiMsg uint8[4]

type OscType byte

type Arg interface {
    GetType() OscType
    GetValue() interface{}
}

type SymbolType string

func (this *SymbolType) GetType() OscType {
    return Symbol
}

func (this *SymbolType) GetValue interface{} {
    return *this
}

type InfinitumType interface{}

func (this *InfinitumType) GetType() OscType {
    return Infinitum
}

func (this *InfinitumType) GetValue interface{} {
    return nil
}

type goTypeWrapper struct {
    Arg
    value interface{}
}

func (this *goTypeWrapper) GetType() o OscType {
    switch i := (*this).(type) {
    case int32:
        o = Int32
    case float32:
        o = Float32
    case string:
        o = String
    case Blob:
        o = BlobCode
    case int64:
        o = Int64
    case Timetag:
        o = TimetagCode
    case float64:
        o = Double
        // no way to automatically detect symbols!
    case byte:
        o = Char
    case MidiMsg:
        o = MidiMsgCode
    case bool:
        if bool(*this) {
            o = True
        } else {
            o = False
        }
    case nil:
        o = Nil
        // no way to detect infinitum
    }
}

const (
    Udp = iota
    Tcp
    Unix
    )

const (
    Int32 OscType = 'i'
    Float OscType = 'f'
    String OscType = 's'
    BlobCode OscType = 'b'
    Int64 OscType = 'h'
    TimetagCode OscType = 't'
    Double OscType = 'd'
    Symbol OscType = 'S'
    Char OscType = 'c'
    MidiMsgCode OscType = 'm'
    True OscType = 'T'
    False OscType = 'F'
    Nil OscType = 'N'
    Infinitum OscType = 'I'
)

const Now = Timetag{0,1}

/* opaque address type */
type Address struct {
    lo_address unsafe.Pointer
    dead bool
}

func NewAddress(host, port string) (ret *Address) {
    ret = new(Address)
    ret.dead = false
    chost := C.CString(host)
    defer C.free(unsafe.Pointer(chost))
    cport := C.CString(port)
    defer C.free(unsafe.Pointer(cport))
    ret.lo_address = C.lo_address_new(chost, cport)
    runtime.SetFinalizer(ret, (*Address).Free)
    return
}

func NewAddressWithProto(proto int, host, port string) (ret *Address) {
    ret = new(Address)
    ret.dead = false
    chost := C.CString(host)
    defer C.free(unsafe.Pointer(chost))
    cport := C.CString(port)
    defer C.free(unsafe.Pointer(cport))
    ret.lo_address = C.lo_address_new_with_proto(proto, chost, cport)
    runtime.SetFinalizer(ret, (*Address).Free)
    return
}

func NewAddressFromUrl(url string) (ret *Address) {
    ret = new(Address)
    ret.dead = false
    curl := C.CString(url)
    defer C.free(unsafe.Pointer(curl))
    ret.lo_address = C.lo_address_new_from_url(curl)
    runtime.SetFinalizer(ret, (*Address).Free)
    return
}

func (this *Address) SetTtl(ttl int) {
    if (this.dead) {
        panic("Method called on dead object")
    }
    C.lo_address_set_ttl(this.lo_address, ttl)
}

func (this *Address) GetTtl() (ttl int) {
    if (this.dead) {
        panic("Method called on dead object")
    }
    ttl = C.lo_address_get_ttl(this.lo_address)
}

func (this *Address) Errno() int {
    if (this.dead) {
        panic("Method called on dead object")
    }
    return C.lo_address_errno(this.lo_address)
}

func (this *Address) Errstr() string {
    if (this.dead) {
        panic("Method called on dead object")
    }
    return C.GoString(C.lo_address_errstr(this.lo_address))
}

func (this *Address) Free() {
    if (this.dead) {
        return
    }
    C.lo_address_free(this.lo_address)
    this.lo_address = nil
    this.dead = true
}

/* Why go through a bunch of junk to use the lo blob type? Just make a byte slice and call lo_blob_new when we add it to a message */
type Blob []byte

/* why use the message type before it's time to send it? */
type Message []Arg

func (this *Message) Send(targ Address, path string) ret int {
    ret = this.SendTimestamped(targ, Now, path)
}

func (this *Message) SendTimestamped(targ Address, time Timetag, path string) ret int {
    // build a new lo_message
    m := C.lo_message_new()
    defer C.lo_message_free(unsafe.Pointer(m))
    for _, arg := range m {
        switch arg.GetType() {
        case Int32:
            C.lo_message_add_int32(m, int32(arg.GetValue()))
        case Float:
            C.lo_message_add_float(m, float32(arg.GetValue()))
        case Blob:
            b := C.lo_message_blob_new(len(Blob(arg)), unsafe.Pointer(arg))
            defer C.lo_blob_free(unsafe.Pointer(b))
            C.lo_message_add_blob(m, b)
        case:

    }
}

type Bundle struct {
    lo_address unsafe.Pointer
}<commit_msg>package builds, starting client<commit_after>package osc

// #cgo LDFLAGS: -llo
// #include <stdlib.h>
// #include "lo/lo.h"
import "C"

import (
    "unsafe"
    "runtime"
    )

/* to implement liblo's high level OSC interface, we need the following:
timetag type
message arg type, can act as int32, int64, float, double, char, unsigned char, uint8[4], and timetag
 */

type Timetag struct {
    Sec, Frac _Ctypedef_uint32_t
}

type MidiMsg [4]uint8

type OscType byte

type Arg interface {
    GetType() OscType
    GetValue() interface{}
}

type SymbolType string

func (this *SymbolType) GetType() OscType {
    return Symbol
}

func (this *SymbolType) GetValue() (interface{}) {
    return *this
}

type InfinitumType struct{}

func (this *InfinitumType) GetType() OscType {
    return Infinitum
}

func (this *InfinitumType) GetValue() interface{} {
    return nil
}

type goTypeWrapper struct {
    Arg
    value interface{}
}

func (this *goTypeWrapper) GetType() (o OscType) {
    switch i := this.value.(type) {
    case int32:
        o = Int32
    case float32:
        o = Float
    case string:
        o = String
    case Blob:
        o = BlobCode
    case int64:
        o = Int64
    case Timetag:
        o = TimetagCode
    case float64:
        o = Double
        // no way to automatically detect symbols!
    case byte:
        o = Char
    case MidiMsg:
        o = MidiMsgCode
    case bool:
        if i, _ := this.value.(bool); i {
            o = True
        } else {
            o = False
        }
    case nil:
        o = Nil
        // no way to detect infinitum
    }
    return
}

const (
    Udp = iota
    Tcp
    Unix
    )

const (
    Int32 OscType = 'i'
    Float OscType = 'f'
    String OscType = 's'
    BlobCode OscType = 'b'
    Int64 OscType = 'h'
    TimetagCode OscType = 't'
    Double OscType = 'd'
    Symbol OscType = 'S'
    Char OscType = 'c'
    MidiMsgCode OscType = 'm'
    True OscType = 'T'
    False OscType = 'F'
    Nil OscType = 'N'
    Infinitum OscType = 'I'
)

var Now = Timetag{0,1}

/* opaque address type */
type Address struct {
    lo_address _Ctypedef_lo_address
    dead bool
}

func NewAddress(host, port *string) (ret *Address) {
    ret = new(Address)
    ret.dead = false
    chost := C.CString(*host)
    defer C.free(unsafe.Pointer(chost))
    cport := C.CString(*port)
    defer C.free(unsafe.Pointer(cport))
    ret.lo_address = C.lo_address_new(chost, cport)
    runtime.SetFinalizer(ret, (*Address).Free)
    return
}

func NewAddressWithProto(proto int, host, port string) (ret *Address) {
    ret = new(Address)
    ret.dead = false
    chost := C.CString(host)
    defer C.free(unsafe.Pointer(chost))
    cport := C.CString(port)
    defer C.free(unsafe.Pointer(cport))
    ret.lo_address = C.lo_address_new_with_proto(C.int(proto), chost, cport)
    runtime.SetFinalizer(ret, (*Address).Free)
    return
}

func NewAddressFromUrl(url string) (ret *Address) {
    ret = new(Address)
    ret.dead = false
    curl := C.CString(url)
    defer C.free(unsafe.Pointer(curl))
    ret.lo_address = C.lo_address_new_from_url(curl)
    runtime.SetFinalizer(ret, (*Address).Free)
    return
}

func (this *Address) SetTtl(ttl int) {
    if (this.dead) {
        panic("Method called on dead object")
    }
    C.lo_address_set_ttl(this.lo_address, C.int(ttl))
}

func (this *Address) GetTtl() (ttl int) {
    if (this.dead) {
        panic("Method called on dead object")
    }
    ttl = int(C.lo_address_get_ttl(this.lo_address))
    return
}

func (this *Address) Errno() int {
    if (this.dead) {
        panic("Method called on dead object")
    }
    return int(C.lo_address_errno(this.lo_address))
}

func (this *Address) Errstr() string {
    if (this.dead) {
        panic("Method called on dead object")
    }
    return C.GoString(C.lo_address_errstr(this.lo_address))
}

func (this *Address) Free() {
    if (this.dead) {
        return
    }
    C.lo_address_free(this.lo_address)
    this.lo_address = nil
    this.dead = true
}

/* Why go through a bunch of junk to use the lo blob type? Just make a byte slice and call lo_blob_new when we add it to a message */
type Blob []byte

/* why use the message type before it's time to send it? */
type Message []Arg

func (this *Message) Send(targ *Address, path string) (ret int) {
    ret = this.SendTimestamped(targ, Now, path)
    return
}

func (this *Message) SendTimestamped(targ *Address, time Timetag, path string) (ret int) {
    // build a new lo_message
    m, ret := this.build_lo_message()
    if m == nil {
        return
    }
    if ret < 0 {
        C.lo_message_free(m)
        return
    }
    defer C.lo_message_free(m)
    s := C.CString(path)
    defer C.free(unsafe.Pointer(s))
    ret = int(C.lo_send_message(targ.lo_address, s, m))
    return
}

func (this *Message) build_lo_message() (m C.lo_message, ret int) {
    m = C.lo_message_new()
    if m == nil {
        ret = -1
        return
    }
    for _, arg := range *this {
        switch arg.GetType() {
        case Int32:
            ret = int(C.lo_message_add_int32(m, _Ctypedef_int32_t(arg.GetValue().(int32))))
        case Float:
            ret = int(C.lo_message_add_float(m, _Ctype_float(arg.GetValue().(float32))))
        case BlobCode:
            a, i := arg.GetValue().(Blob)
            if !i {
                ret = -1
                break
            }

            b := C.lo_blob_new(_Ctypedef_int32_t(len(a)), unsafe.Pointer(&a))
            if b == nil {
                ret = -1
                break
            }
            defer C.lo_blob_free(_Ctypedef_lo_blob(b))
            ret = int(C.lo_message_add_blob(m, b))
        case Int64:
            ret = int(C.lo_message_add_int64(m, _Ctypedef_int64_t(arg.GetValue().(int64))))
        case TimetagCode:
            ret = int(C.lo_message_add_timetag(m, C.lo_timetag{arg.GetValue().(Timetag).Sec, arg.GetValue().(Timetag).Frac}))
        case Double:
            ret = int(C.lo_message_add_double(m, _Ctype_double(arg.GetValue().(float64))))
        case Symbol:
            s := C.CString(arg.GetValue().(string))
            if s == nil {
                ret = -1
                break
            }
            defer C.free(unsafe.Pointer(s))
            ret = int(C.lo_message_add_symbol(m, s))
        case Char:
            ret = int(C.lo_message_add_char(m, arg.GetValue().(C.char)))
        case MidiMsgCode:
            mm := arg.GetValue().(MidiMsg)
            ret = int(C.lo_message_add_midi(m, (*C.uint8_t)(unsafe.Pointer(&mm))))
        case True:
            ret = int(C.lo_message_add_true(m))
        case False:
            ret = int(C.lo_message_add_false(m))
        case Nil:
            ret = int(C.lo_message_add_nil(m))
        case Infinitum:
            ret = int(C.lo_message_add_infinitum(m))
        default:
            ret = -1
        }
        if ret < 0 {
            C.lo_message_free(m)
            m = nil
            return
        }
    }
    return
}

type MsgPath struct {
    Path string
    Msg *Message
}

type Bundle struct {
    Time Timetag
    MsgPaths []MsgPath
}

func (this *Bundle) Send(targ Address) (ret int) {
    ret = 0
    b := C.lo_bundle_new(C.lo_timetag{this.Time.Sec, this.Time.Frac})
    if b == nil {
        ret = -1
        return
    }
    defer C.lo_bundle_free_messages(b)
    for _, r := range this.MsgPaths {
        p := C.CString(r.Path)
        defer C.free(unsafe.Pointer(p))
        m, ret := r.Msg.build_lo_message()
        if ret < 0 {
            return
        }

        ret = int(C.lo_bundle_add_message(b, p, m))
        if ret < 0 {
            return
        }
    }
    ret = int(C.lo_send_bundle(targ.lo_address, b))
    return
}<|endoftext|>


<commit_before>package pawn

import (
	"strings"
	"text/scanner"
)

type PGN struct {
	Tags map[string]string
}

func NewPGN() PGN {
	return PGN{
		Tags: map[string]string{},
	}
}

type PGNParser struct {
	pgn PGN
}

func NewPGNParser() PGNParser {
	return PGNParser{pgn: NewPGN()}
}

func (p PGNParser) ParseFromString(str string) PGN {
	reader := strings.NewReader(str)
	scanner := scanner.Scanner{}
	scanner.Init(reader)

	return p.ParseFromScanner(&scanner)
}

func (p PGNParser) ParseFromScanner(sc *scanner.Scanner) PGN {
	ParseTags(sc, &p.pgn)

	return p.pgn
}

func ParsePGN(str string) PGN {
	return NewPGNParser().ParseFromString(str)
}

func ParseTags(sc *scanner.Scanner, pgn *PGN) {
	scan := sc.Peek()

	for scan != scanner.EOF {
		switch scan {
		case '[', ']', '\n', '\r':
			scan = sc.Next()
		case '1': // First move; all tags have been read
			return
		default:
			sc.Scan()
			tag := sc.TokenText()
			sc.Scan()
			value := sc.TokenText()

			pgn.Tags[tag] = strings.Trim(value, "\"")
		}
		scan = sc.Peek()
	}
}

func ParseMoves(sc *scanner.Scanner, pgn *PGN) {
	sc.Mode = scanner.ScanIdents | scanner.ScanChars | scanner.ScanInts | scanner.ScanStrings
}
<commit_msg>Verify CI behavior<commit_after>package pawn

import (
	"strings"
	"text/scanner"
)

type PGN struct {
	Tags map[string]string
}

func NewPGN() PGN {
	return PGN{
		Tags: map[string]string{},
	}
}

type PGNParser struct {
	pgn PGN
}

func NewPGNParser() PGNParser {
	return PGNParser{pgn: NewPGN()}
}

func (p PGNParser) ParseFromString(str string) PGN {
	reader := strings.NewReader(str)
	scanner := scanner.Scanner{}
	scanner.Init(reader)

	return p.ParseFromScanner(&scanner)
}

func (p PGNParser) ParseFromScanner(sc *scanner.Scanner) PGN {
	ParseTags(sc, &p.pgn)

	return p.pgn
}

func ParsePGN(str string) PGN {
	return NewPGNParser().ParseFromString(str)
}

func ParseTags(sc *scanner.Scanner, pgn *PGN) {
	scan := sc.Peek()

	for scan != scanner.EOF {
		switch scan {
		case '[', ']', '\n', '\r':
			scan = sc.Next()
		case '1': // First move; all tags have been read
			return
		default:
			sc.Scan()
			tag := sc.TokenText()
			sc.Scan()
			value := sc.TokenText()

			pgn.Tags[tag] = strings.Trim(value, "\"")
		}
		scan = sc.Peek()
	}
}

func ParseMoves(sc *scanner.Scanner, pgn *PGN) {
	// sc.Mode = scanner.ScanIdents | scanner.ScanChars | scanner.ScanInts | scanner.ScanStrings
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"io"
	"net/http"
	"strconv"
	"strings"

	"github.com/PuerkitoBio/goquery"
	"github.com/koding/multiconfig"
)

var conf = loadConfig()

func loadConfig() *DefaultConf {
	m := multiconfig.New()
	conf := new(DefaultConf)
	m.MustLoad(conf)

	return conf
}

func main() {

	switch conf.Mode {
	case "view":
		fetchMultiPages(conf.Board, conf.Page)
	}
}

func fetchSingle(url string, str chan string) {
	resp := fetch(url)
	defer resp.Body.Close()

	doc := getDocument(resp)
	tmp := ""
	doc.Find("div.title").Each(func(i int, s *goquery.Selection) {
		link, _ := s.Find("a").Attr("href")
		title := strings.TrimSpace(s.Text())
		if len(link) != 0 {
			tmp += title + "\t" + "https://www.ptt.cc" + link + "\n"
		}
	})
	str <- tmp
}

func fetchPages(url string, ch chan int) {
	resp := fetch(url)
	defer resp.Body.Close()

	doc := getDocument(resp)
	href, _ := doc.Find("div.action-bar").Find("a.btn").Eq(3).Attr("href")
	pages, _ := strconv.Atoi(strings.Trim(strings.Split(strings.Split(href, "/")[3], ".")[0], "index"))
	ch <- pages
}

func fetchMultiPages(board string, pre int) {
	fmt.Println("Do fetch multiple pages")
	ch := make(chan int)
	url := conf.BaseUrl + board + "/index.html"
	go fetchPages(url, ch)
	p := <-ch

	var pagesURL = make([]string, pre+1)
	for i := pre; i > 0; i-- {
		pagesURL[i] = conf.BaseUrl + board + "/index" + strconv.Itoa(p-i) + ".html"
		fmt.Println("\n" + pagesURL[i] + "\n")
		s := make(chan string)
		go fetchSingle(pagesURL[i], s)
		result := <-s
		fmt.Println(result)
	}
}

func getDocument(resp *http.Response) *goquery.Document {
	r := io.Reader(resp.Body)
	doc, _ := goquery.NewDocumentFromReader(r)
	return doc
}

func fetch(url string) *http.Response {
	resp, _ := http.Get(url)
	return resp
}
<commit_msg>Fix wrong page<commit_after>package main

import (
	"fmt"
	"io"
	"net/http"
	"strconv"
	"strings"

	"github.com/PuerkitoBio/goquery"
	"github.com/koding/multiconfig"
)

var conf = loadConfig()

func loadConfig() *DefaultConf {
	m := multiconfig.New()
	conf := new(DefaultConf)
	m.MustLoad(conf)

	return conf
}

func main() {

	switch conf.Mode {
	case "view":
		fetchMultiPages(conf.Board, conf.Page)
	}
}

func fetchSingle(url string, str chan string) {
	resp := fetch(url)
	defer resp.Body.Close()

	doc := getDocument(resp)
	tmp := ""
	doc.Find("div.title").Each(func(i int, s *goquery.Selection) {
		link, _ := s.Find("a").Attr("href")
		title := strings.TrimSpace(s.Text())
		if len(link) != 0 {
			tmp += title + "\t" + "https://www.ptt.cc" + link + "\n"
		}
	})
	str <- tmp
}

func fetchPages(url string, ch chan int) {
	resp := fetch(url)
	defer resp.Body.Close()

	doc := getDocument(resp)
	href, _ := doc.Find("div.action-bar").Find("a.btn").Eq(3).Attr("href")
	pages, _ := strconv.Atoi(strings.Trim(strings.Split(strings.Split(href, "/")[3], ".")[0], "index"))
	ch <- pages
}

func fetchMultiPages(board string, pre int) {
	fmt.Println("Do fetch multiple pages")
	ch := make(chan int)
	url := conf.BaseUrl + board + "/index.html"
	go fetchPages(url, ch)
	p := <-ch

	var pagesURL = make([]string, pre+1)
	for i := pre; i >= 0; i-- {
		pagesURL[i] = conf.BaseUrl + board + "/index" + strconv.Itoa(p+1-i) + ".html"
		fmt.Println("\n" + pagesURL[i] + "\n")
		s := make(chan string)
		go fetchSingle(pagesURL[i], s)
		result := <-s
		fmt.Println(result)
	}
}

func getDocument(resp *http.Response) *goquery.Document {
	r := io.Reader(resp.Body)
	doc, _ := goquery.NewDocumentFromReader(r)
	return doc
}

func fetch(url string) *http.Response {
	resp, _ := http.Get(url)
	return resp
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"log"
	"net/http"
	"os"
	"runtime"
	"strconv"
	"strings"

	"github.com/garyburd/redigo/redis"
	"github.com/gorilla/mux"
)

func stringToFloat32(vString string) (v float32, err error) {
	v64, err := strconv.ParseFloat(vString, 32)
	if err != nil {
		return
	}
	v = float32(v64)
	return
}

func newFloat32Matrix(height, width int) [][]float32 {
	var mx [][]float32 = make([][]float32, height)
	for i := 0; i < width; i++ {
		mx[i] = make([]float32, width)
	}
	return mx
}

func matrixPosition(width, i, j int) int {
	return i*width + j
}

func transpose(mx [][]float32) (mxt [][]float32) {
	if len(mx) == 0 {
		return
	}
	mxt = newFloat32Matrix(len(mx), len(mx[0]))

	for i := range mx {
		for j := range mx[i] {
			mxt[i][j] = mx[j][i]
		}
	}
	return
}

func weightKey(url, profile string) string {
	return strings.Join([]string{url, profile}, "|")
}

func weightKeys(urls, profiles []string) []interface{} {
	var keys = make([]interface{}, 0, len(urls)*len(profiles))
	for _, url := range urls {
		for _, profile := range profiles {
			key := weightKey(url, profile)
			keys = append(keys, key)
		}
	}
	return keys
}

func getWeight(conn redis.Conn, url, profile string) (w float32, err error) {
	key := weightKey(url, profile)

	weight, err := redis.String(conn.Do("GET", key))
	if err == redis.ErrNil {
		weight = "0"
	} else if err != nil {
		return
	}

	return stringToFloat32(weight)
}

func getWeights(conn redis.Conn, urls, profiles []string) ([][]float32, error) {
	keys := weightKeys(urls, profiles)

	// TODO: how to pass []string?
	weightsString, err := redis.Strings(conn.Do("MGET", keys...))
	if err != nil {
		return nil, err
	}

	urlProfile := newFloat32Matrix(len(urls), len(profiles))

	for i := range urls {
		for j := range profiles {
			pos := matrixPosition(len(profiles), i, j)

			wString := weightsString[pos]
			if wString == "" {
				continue
			}

			w, err := stringToFloat32(wString)
			if err != nil {
				return nil, err
			}

			urlProfile[i][j] = w
		}
	}

	return urlProfile, nil
}

type Similar interface {
	Similar(v []float32) float32
}

type Session []float32

func newSession(urlsVisited, urls []string) Session {
	urlPos := make(map[string]int)
	for i, url := range urls {
		urlPos[url] = i
	}

	s := make(Session, len(urls))
	for _, url := range urlsVisited {
		if pos, ok := urlPos[url]; ok {
			s[pos] = 1
		}
	}

	return s
}

func (self Session) Similar(v []float32) float32 {
	return 1
}

type ServerState struct {
	urls              []string
	profiles          []string
	urlProfileWeights [][]float32
}

// TODO: add timeouts
func newServerState() (state *ServerState, err error) {
	conn, err := redis.Dial("tcp", "127.0.0.1:6379")
	if err != nil {
		return
	}
	defer conn.Close()

	urls, err := redis.Strings(conn.Do("SMEMBERS", "urls"))
	if err != nil {
		return
	}

	profiles, err := redis.Strings(conn.Do("SMEMBERS", "profiles"))
	if err != nil {
		return
	}

	urlProfileWeights, err := getWeights(conn, urls, profiles)
	if err != nil {
		return
	}

	state = new(ServerState)
	state.urls = urls
	state.profiles = profiles
	state.urlProfileWeights = urlProfileWeights

	return
}

type Request struct {
	Urls []string `json:"urls"`
}

type Response struct {
	Recommendation map[string]float32 `json:"recommendation"`
	Err            string             `json:"error"`

	state *ServerState
}

func countSimilarities(urlProfileWeights [][]float32, session Similar) (similarities []float32) {
	profileUrlWeights := transpose(urlProfileWeights)

	similarities = make([]float32, len(profileUrlWeights))
	for i, profile := range profileUrlWeights {
		s := session.Similar(profile)
		similarities[i] = s
	}
	return
}

func (self *Response) countRecommendation(session Similar) (recommendation map[string]float32, err error) {
	similarities := countSimilarities(self.state.urlProfileWeights, session)
	log.Println(similarities)

	// Мамдани епта
	for i, url := range self.state.urls {
		for j, profile := range self.state.profiles {
			log.Println(url, profile, self.state.urlProfileWeights[i][j])
			//min(similarity, freq)
		}
		//max
	}

	return
}

func (self *Response) SetRecommendation(urls []string) (err error) {
	session := newSession(urls, self.state.urls)
	self.Recommendation, err = self.countRecommendation(session)
	return
}

func recommendHandler(st *ServerState) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("Content-Type", "application/json")

		decoder := json.NewDecoder(r.Body)
		encoder := json.NewEncoder(w)

		req := new(Request)
		resp := &Response{state: st}

		var err error

		defer func() {
			if err != nil {
				log.Println(err)
				resp.Err = err.Error()
			}

			err := encoder.Encode(resp)
			if err != nil {
				log.Println(err)
			}
		}()

		err = decoder.Decode(req)
		if err != nil {
			return
		}

		err = resp.SetRecommendation(req.Urls)
	}
}

func startRecommendationServer() error {
	state, err := newServerState()
	if err != nil {
		return err
	}

	r := mux.NewRouter()
	r.HandleFunc("/recommend", recommendHandler(state)).Methods("POST")
	http.Handle("/", r)

	return http.ListenAndServe(":"+os.Getenv("PORT"), nil)
}

func main() {
	err := startRecommendationServer()
	if err != nil {
		log.Fatal(err)
	}
}

func init() {
	runtime.GOMAXPROCS(runtime.NumCPU())
}
<commit_msg>added min max<commit_after>package main

import (
	"encoding/json"
	"log"
	"math"
	"net/http"
	"os"
	"runtime"
	"strconv"
	"strings"

	"github.com/garyburd/redigo/redis"
	"github.com/gorilla/mux"
)

func max(numbers []float32) float32 {
	if len(numbers) == 0 {
		return 0
	}
	var max float64 = float64(numbers[0])

	for i := 1; i < len(numbers); i++ {
		max = math.Max(max, float64(numbers[i]))
	}
	return float32(max)
}

func stringToFloat32(vString string) (v float32, err error) {
	v64, err := strconv.ParseFloat(vString, 32)
	if err != nil {
		return
	}
	v = float32(v64)
	return
}

func newFloat32Matrix(height, width int) [][]float32 {
	var mx [][]float32 = make([][]float32, height)
	for i := 0; i < width; i++ {
		mx[i] = make([]float32, width)
	}
	return mx
}

func matrixPosition(width, i, j int) int {
	return i*width + j
}

func transpose(mx [][]float32) (mxt [][]float32) {
	if len(mx) == 0 {
		return
	}
	mxt = newFloat32Matrix(len(mx), len(mx[0]))

	for i := range mx {
		for j := range mx[i] {
			mxt[i][j] = mx[j][i]
		}
	}
	return
}

//

func weightKey(url, profile string) string {
	return strings.Join([]string{url, profile}, "|")
}

func weightKeys(urls, profiles []string) []interface{} {
	var keys = make([]interface{}, 0, len(urls)*len(profiles))
	for _, url := range urls {
		for _, profile := range profiles {
			key := weightKey(url, profile)
			keys = append(keys, key)
		}
	}
	return keys
}

func getWeight(conn redis.Conn, url, profile string) (w float32, err error) {
	key := weightKey(url, profile)

	weight, err := redis.String(conn.Do("GET", key))
	if err == redis.ErrNil {
		weight = "0"
	} else if err != nil {
		return
	}

	return stringToFloat32(weight)
}

func getWeights(conn redis.Conn, urls, profiles []string) ([][]float32, error) {
	keys := weightKeys(urls, profiles)

	// TODO: how to pass []string?
	weightsString, err := redis.Strings(conn.Do("MGET", keys...))
	if err != nil {
		return nil, err
	}

	urlProfile := newFloat32Matrix(len(urls), len(profiles))

	for i := range urls {
		for j := range profiles {
			pos := matrixPosition(len(profiles), i, j)

			wString := weightsString[pos]
			if wString == "" {
				continue
			}

			w, err := stringToFloat32(wString)
			if err != nil {
				return nil, err
			}

			urlProfile[i][j] = w
		}
	}

	return urlProfile, nil
}

//

type Similar interface {
	Similar(v []float32) float32
}

type Session []float32

func newSession(urlsVisited, urls []string) Session {
	urlPos := make(map[string]int)
	for i, url := range urls {
		urlPos[url] = i
	}

	s := make(Session, len(urls))
	for _, url := range urlsVisited {
		if pos, ok := urlPos[url]; ok {
			s[pos] = 1
		}
	}

	return s
}

func (self Session) Similar(v []float32) float32 {
	return 1
}

//

type ServerState struct {
	urls              []string
	profiles          []string
	urlProfileWeights [][]float32
}

// TODO: add timeouts
func newServerState() (state *ServerState, err error) {
	conn, err := redis.Dial("tcp", "127.0.0.1:6379")
	if err != nil {
		return
	}
	defer conn.Close()

	urls, err := redis.Strings(conn.Do("SMEMBERS", "urls"))
	if err != nil {
		return
	}

	profiles, err := redis.Strings(conn.Do("SMEMBERS", "profiles"))
	if err != nil {
		return
	}

	urlProfileWeights, err := getWeights(conn, urls, profiles)
	if err != nil {
		return
	}

	state = new(ServerState)
	state.urls = urls
	state.profiles = profiles
	state.urlProfileWeights = urlProfileWeights

	return
}

type Request struct {
	Urls []string `json:"urls"`
}

type Response struct {
	Recommendation map[string]float32 `json:"recommendation"`
	Err            string             `json:"error"`

	state *ServerState
}

func countSimilarities(urlProfileWeights [][]float32, session Similar) (similarities []float32) {
	profileUrlWeights := transpose(urlProfileWeights)

	similarities = make([]float32, len(profileUrlWeights))
	for i, profile := range profileUrlWeights {
		s := session.Similar(profile)
		similarities[i] = s
	}
	return
}

// Mamdani inference
func (self *Response) countRecommendation(session Similar) (recommendation map[string]float32, err error) {
	similarities := countSimilarities(self.state.urlProfileWeights, session)

	recommendation = make(map[string]float32)
	weights := make([]float32, len(self.state.profiles))
	for i, url := range self.state.urls {
		for j := range self.state.profiles {
			min := float32(math.Min(float64(similarities[j]), float64(self.state.urlProfileWeights[i][j])))
			weights[j] = min
		}
		recommendation[url] = max(weights)
	}

	return
}

func (self *Response) SetRecommendation(urls []string) (err error) {
	session := newSession(urls, self.state.urls)
	self.Recommendation, err = self.countRecommendation(session)
	return
}

func recommendHandler(st *ServerState) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("Content-Type", "application/json")

		decoder := json.NewDecoder(r.Body)
		encoder := json.NewEncoder(w)

		req := new(Request)
		resp := &Response{state: st}

		var err error

		defer func() {
			if err != nil {
				log.Println(err)
				resp.Err = err.Error()
			}

			err := encoder.Encode(resp)
			if err != nil {
				log.Println(err)
			}
		}()

		err = decoder.Decode(req)
		if err != nil {
			return
		}

		err = resp.SetRecommendation(req.Urls)
	}
}

func startRecommendationServer() error {
	state, err := newServerState()
	if err != nil {
		return err
	}

	r := mux.NewRouter()
	r.HandleFunc("/recommend", recommendHandler(state)).Methods("POST")
	http.Handle("/", r)

	return http.ListenAndServe(":"+os.Getenv("PORT"), nil)
}

func main() {
	err := startRecommendationServer()
	if err != nil {
		log.Fatal(err)
	}
}

func init() {
	runtime.GOMAXPROCS(runtime.NumCPU())
}
<|endoftext|>


<commit_before>package fixtures

import (
	"fmt"
	"sort"
	"strings"
	"time"
)

const (
	onInsertNow    = "ON_INSERT_NOW()"
	onUpdateNow    = "ON_UPDATE_NOW()"
	postgresDriver = "postgres"
)

// Row represents a single database row
type Row struct {
	Table              string
	PK                 map[string]interface{}
	Fields             map[string]interface{}
	insertColumnLength int
	updateColumnLength int
	pkColumns          []string
	pkValues           []interface{}
	insertColumns      []string
	updateColumns      []string
	insertValues       []interface{}
	updateValues       []interface{}
	rawInsertValues    []interface{}
	rawUpdateValues    []interface{}
}

// Init loads internal struct variables
func (row *Row) Init() {
	// Initial values
	row.insertColumnLength = len(row.PK) + len(row.Fields)
	row.updateColumnLength = len(row.PK) + len(row.Fields)
	row.pkColumns = make([]string, 0)
	row.pkValues = make([]interface{}, 0)
	row.insertColumns = make([]string, 0)
	row.updateColumns = make([]string, 0)
	row.insertValues = make([]interface{}, 0)
	row.updateValues = make([]interface{}, 0)
	row.rawInsertValues = make([]interface{}, 0)
	row.rawUpdateValues = make([]interface{}, 0)
	// Get and sort map keys
	var i int
	pkKeys := make([]string, len(row.PK))
	i = 0
	for pkKey := range row.PK {
		pkKeys[i] = pkKey
		i++
	}
	sort.Strings(pkKeys)
	fieldKeys := make([]string, len(row.Fields))
	i = 0
	for fieldKey := range row.Fields {
		fieldKeys[i] = fieldKey
		i++
	}
	sort.Strings(fieldKeys)

	// Primary keys
	for _, pkKey := range pkKeys {
		row.pkColumns = append(row.pkColumns, pkKey)
		row.pkValues = append(row.pkValues, row.PK[pkKey])
		row.insertColumns = append(row.insertColumns, pkKey)
		row.updateColumns = append(row.updateColumns, pkKey)
		row.appendValue("insert", row.PK[pkKey])
		row.appendValue("update", row.PK[pkKey])
	}

	// Rest of the fields
	for _, fieldKey := range fieldKeys {
		sv, ok := row.Fields[fieldKey].(string)
		if ok && sv == onInsertNow {
			row.insertColumns = append(row.insertColumns, fieldKey)
			row.appendValue("insert", time.Now())
			row.updateColumnLength--
			continue
		}
		if ok && sv == onUpdateNow {
			row.updateColumns = append(row.updateColumns, fieldKey)
			row.appendValue("update", time.Now())
			row.insertColumnLength--
			continue
		}
		row.insertColumns = append(row.insertColumns, fieldKey)
		row.updateColumns = append(row.updateColumns, fieldKey)
		row.appendValue("insert", row.Fields[fieldKey])
		row.appendValue("update", row.Fields[fieldKey])
	}
}

// GetInsertColumnsLength returns number of columns for INSERT query
func (row *Row) GetInsertColumnsLength() int {
	return row.insertColumnLength
}

// GetInsertValuesLength returns number of values for INSERT query
func (row *Row) GetInsertValuesLength() int {
	return len(row.insertValues)
}

// GetUpdateColumnsLength returns number of columns for UDPATE query
func (row *Row) GetUpdateColumnsLength() int {
	return row.updateColumnLength
}

// GetUpdateValuesLength returns number of values for UDPATE query
func (row *Row) GetUpdateValuesLength() int {
	return len(row.updateValues)
}

// GetInsertColumns returns a slice of column names for INSERT query
func (row *Row) GetInsertColumns() []string {
	escapedColumns := make([]string, len(row.insertColumns))
	for i, insertColumn := range row.insertColumns {
		escapedColumns[i] = fmt.Sprintf("\"%s\"", insertColumn)
	}
	return escapedColumns
}

// GetUpdateColumns returns a slice of column names for UPDATE query
func (row *Row) GetUpdateColumns() []string {
	escapedColumns := make([]string, len(row.updateColumns))
	for i, updateColumn := range row.updateColumns {
		escapedColumns[i] = fmt.Sprintf("\"%s\"", updateColumn)
	}
	return escapedColumns
}

// GetInsertValues returns a slice of values for INSERT query
func (row *Row) GetInsertValues() []interface{} {
	return row.insertValues
}

// GetUpdateValues returns a slice of values for UPDATE query
func (row *Row) GetUpdateValues() []interface{} {
	return row.updateValues
}

// GetInsertPlaceholders returns a slice of placeholders for INSERT query
func (row *Row) GetInsertPlaceholders(driver string) []string {
	placeholders := make([]string, row.GetInsertColumnsLength())
	for i, j := 0, 0; i < row.GetInsertColumnsLength(); i++ {
		val := row.rawInsertValues[i]
		switch v := val.(type) {
		case string:
			if strings.HasPrefix(v, "RAW=") {
				placeholders[i] = strings.TrimPrefix(v, "RAW=")
				continue
			}
		}
		if driver == postgresDriver {
			placeholders[i] = fmt.Sprintf("$%d", j+1)
			j++
		} else {
			placeholders[i] = "?"
		}
	}
	return placeholders
}

// GetUpdatePlaceholders returns a slice of placeholders for UPDATE query
func (row *Row) GetUpdatePlaceholders(driver string) []string {
	placeholders := make([]string, row.GetUpdateColumnsLength())
	j := 0
	for i, c := range row.GetUpdateColumns() {
		val := row.rawUpdateValues[i]
		switch v := val.(type) {
		case string:
			if strings.HasPrefix(v, "RAW=") {
				placeholders[i] = fmt.Sprintf("%s = %s", c, strings.TrimPrefix(v, "RAW="))
				continue
			}
		}
		if driver == postgresDriver {
			placeholders[i] = fmt.Sprintf("%s = $%d", c, j+1)
			j++
		} else {
			placeholders[i] = fmt.Sprintf("%s = ?", c)
		}
	}
	return placeholders
}

// GetWhere returns a where condition based on primary key with placeholders
func (row *Row) GetWhere(driver string, i int) string {
	wheres := make([]string, len(row.PK))
	j := i
	for _, c := range row.pkColumns {
		if driver == postgresDriver {
			wheres[i-j] = fmt.Sprintf("%s = $%d", c, i+1)
		} else {
			wheres[i-j] = fmt.Sprintf("%s = ?", c)
		}
		i++
	}
	return strings.Join(wheres, " AND ")
}

// GetPKValues returns a slice of primary key values
func (row *Row) GetPKValues() []interface{} {
	return row.pkValues
}

func (row *Row) appendValue(queryType string, val interface{}) {
	sv, ok := val.(string)
	if !ok || !strings.HasPrefix(sv, "RAW=") {
		switch queryType {
		case "insert":
			row.insertValues = append(row.insertValues, val)
		case "update":
			row.updateValues = append(row.updateValues, val)
		}
	}
	switch queryType {
	case "insert":
		row.rawInsertValues = append(row.rawInsertValues, val)
	case "update":
		row.rawUpdateValues = append(row.rawUpdateValues, val)
	}
}
<commit_msg> Add support for raw sql as primary key values<commit_after>package fixtures

import (
	"fmt"
	"sort"
	"strings"
	"time"
)

const (
	onInsertNow    = "ON_INSERT_NOW()"
	onUpdateNow    = "ON_UPDATE_NOW()"
	postgresDriver = "postgres"
)

// Row represents a single database row
type Row struct {
	Table              string
	PK                 map[string]interface{}
	Fields             map[string]interface{}
	insertColumnLength int
	updateColumnLength int
	pkColumns          []string
	pkValues           []interface{}
	rawPkValues        []interface{}
	insertColumns      []string
	updateColumns      []string
	insertValues       []interface{}
	updateValues       []interface{}
	rawInsertValues    []interface{}
	rawUpdateValues    []interface{}
}

// Init loads internal struct variables
func (row *Row) Init() {
	// Initial values
	row.insertColumnLength = len(row.PK) + len(row.Fields)
	row.updateColumnLength = len(row.PK) + len(row.Fields)
	row.pkColumns = make([]string, 0)
	row.pkValues = make([]interface{}, 0)
	row.insertColumns = make([]string, 0)
	row.updateColumns = make([]string, 0)
	row.insertValues = make([]interface{}, 0)
	row.updateValues = make([]interface{}, 0)
	row.rawInsertValues = make([]interface{}, 0)
	row.rawUpdateValues = make([]interface{}, 0)
	// Get and sort map keys
	var i int
	pkKeys := make([]string, len(row.PK))
	i = 0
	for pkKey := range row.PK {
		pkKeys[i] = pkKey
		i++
	}
	sort.Strings(pkKeys)
	fieldKeys := make([]string, len(row.Fields))
	i = 0
	for fieldKey := range row.Fields {
		fieldKeys[i] = fieldKey
		i++
	}
	sort.Strings(fieldKeys)

	// Primary keys
	for _, pkKey := range pkKeys {
		row.pkColumns = append(row.pkColumns, pkKey)
		row.appendValue("pk", row.PK[pkKey])
		row.insertColumns = append(row.insertColumns, pkKey)
		row.updateColumns = append(row.updateColumns, pkKey)
		row.appendValue("insert", row.PK[pkKey])
		row.appendValue("update", row.PK[pkKey])
	}

	// Rest of the fields
	for _, fieldKey := range fieldKeys {
		sv, ok := row.Fields[fieldKey].(string)
		if ok && sv == onInsertNow {
			row.insertColumns = append(row.insertColumns, fieldKey)
			row.appendValue("insert", time.Now())
			row.updateColumnLength--
			continue
		}
		if ok && sv == onUpdateNow {
			row.updateColumns = append(row.updateColumns, fieldKey)
			row.appendValue("update", time.Now())
			row.insertColumnLength--
			continue
		}
		row.insertColumns = append(row.insertColumns, fieldKey)
		row.updateColumns = append(row.updateColumns, fieldKey)
		row.appendValue("insert", row.Fields[fieldKey])
		row.appendValue("update", row.Fields[fieldKey])
	}
}

// GetInsertColumnsLength returns number of columns for INSERT query
func (row *Row) GetInsertColumnsLength() int {
	return row.insertColumnLength
}

// GetInsertValuesLength returns number of values for INSERT query
func (row *Row) GetInsertValuesLength() int {
	return len(row.insertValues)
}

// GetUpdateColumnsLength returns number of columns for UDPATE query
func (row *Row) GetUpdateColumnsLength() int {
	return row.updateColumnLength
}

// GetUpdateValuesLength returns number of values for UDPATE query
func (row *Row) GetUpdateValuesLength() int {
	return len(row.updateValues)
}

// GetInsertColumns returns a slice of column names for INSERT query
func (row *Row) GetInsertColumns() []string {
	escapedColumns := make([]string, len(row.insertColumns))
	for i, insertColumn := range row.insertColumns {
		escapedColumns[i] = fmt.Sprintf("\"%s\"", insertColumn)
	}
	return escapedColumns
}

// GetUpdateColumns returns a slice of column names for UPDATE query
func (row *Row) GetUpdateColumns() []string {
	escapedColumns := make([]string, len(row.updateColumns))
	for i, updateColumn := range row.updateColumns {
		escapedColumns[i] = fmt.Sprintf("\"%s\"", updateColumn)
	}
	return escapedColumns
}

// GetInsertValues returns a slice of values for INSERT query
func (row *Row) GetInsertValues() []interface{} {
	return row.insertValues
}

// GetUpdateValues returns a slice of values for UPDATE query
func (row *Row) GetUpdateValues() []interface{} {
	return row.updateValues
}

// GetInsertPlaceholders returns a slice of placeholders for INSERT query
func (row *Row) GetInsertPlaceholders(driver string) []string {
	placeholders := make([]string, row.GetInsertColumnsLength())
	for i, j := 0, 0; i < row.GetInsertColumnsLength(); i++ {
		val := row.rawInsertValues[i]
		switch v := val.(type) {
		case string:
			if strings.HasPrefix(v, "RAW=") {
				placeholders[i] = strings.TrimPrefix(v, "RAW=")
				continue
			}
		}
		if driver == postgresDriver {
			placeholders[i] = fmt.Sprintf("$%d", j+1)
			j++
		} else {
			placeholders[i] = "?"
		}
	}
	return placeholders
}

// GetUpdatePlaceholders returns a slice of placeholders for UPDATE query
func (row *Row) GetUpdatePlaceholders(driver string) []string {
	placeholders := make([]string, row.GetUpdateColumnsLength())
	j := 0
	for i, c := range row.GetUpdateColumns() {
		val := row.rawUpdateValues[i]
		switch v := val.(type) {
		case string:
			if strings.HasPrefix(v, "RAW=") {
				placeholders[i] = fmt.Sprintf("%s = %s", c, strings.TrimPrefix(v, "RAW="))
				continue
			}
		}
		if driver == postgresDriver {
			placeholders[i] = fmt.Sprintf("%s = $%d", c, j+1)
			j++
		} else {
			placeholders[i] = fmt.Sprintf("%s = ?", c)
		}
	}
	return placeholders
}

// GetWhere returns a where condition based on primary key with placeholders
func (row *Row) GetWhere(driver string, i int) string {
	wheres := make([]string, len(row.PK))
	start, j := i, i
	for _, c := range row.pkColumns {
		val := row.rawPkValues[i-start]
		i++
		switch v := val.(type) {
		case string:
			if strings.HasPrefix(v, "RAW=") {
				wheres[i-1-start] = fmt.Sprintf("%s = %s", c, strings.TrimPrefix(v, "RAW="))

				continue
			}
		}
		if driver == postgresDriver {
			wheres[i-1-start] = fmt.Sprintf("%s = $%d", c, j+1)
			j++
		} else {
			wheres[i-1-start] = fmt.Sprintf("%s = ?", c)
		}

	}
	return strings.Join(wheres, " AND ")
}

// GetPKValues returns a slice of primary key values
func (row *Row) GetPKValues() []interface{} {
	return row.pkValues
}

func (row *Row) appendValue(queryType string, val interface{}) {
	sv, ok := val.(string)
	if !ok || !strings.HasPrefix(sv, "RAW=") {
		switch queryType {
		case "insert":
			row.insertValues = append(row.insertValues, val)
		case "update":
			row.updateValues = append(row.updateValues, val)
		case "pk":
			row.pkValues = append(row.pkValues, val)
		}
	}
	switch queryType {
	case "insert":
		row.rawInsertValues = append(row.rawInsertValues, val)
	case "update":
		row.rawUpdateValues = append(row.rawUpdateValues, val)
	case "pk":
		row.rawPkValues = append(row.rawPkValues, val)
	}
}
<|endoftext|>


<commit_before>package feed

import (
	"encoding/xml"
	"errors"
	"fmt"
	"strings"
	"time"
)

type RSSFeed struct {
	Title               string
	Link                string
	Description         string
	Language            string
	Copyright           string
	ManagingEditor      string
	WebMaster           string
	PubDate             string
	PubDateParsed       time.Time
	LastBuildDate       string
	LastBuildDateParsed time.Time
	Categories          []string
	Generator           string
	Docs                string
	TTL                 string
	Image               RSSImage
	Rating              string
	SkipHours           []string
	SkipDays            []string
	Items               []RSSItem
	Version             string
	Extensions          map[string]interface{}
}

type RSSItem struct {
	Title         string
	Link          string
	Description   string
	Author        string
	Categories    []string
	Comments      string
	Enclosure     RSSEnclosure
	Guid          RSSGuid
	PubDate       string
	PubDateParsed time.Time
	Source        string
	Extensions    map[string]interface{}
}

type RSSImage struct {
	URL    string
	Link   string
	Width  string
	Height string
}

type RSSEnclosure struct {
	URL    string
	Length string
	Type   string
}

type RSSGuid struct {
	Value       string
	IsPermalink string
}

func ParseRSSFeed(feed string) (*RSSFeed, error) {
	rss := &RSSFeed{}

	d := xml.NewDecoder(strings.NewReader(feed))
	d.Strict = false

	for {
		token, err := d.Token()

		if err != nil {
			return nil, err
		}

		if token == nil {
			return nil, errors.New("No root node found.")
		}

		switch t := token.(type) {
		case xml.StartElement:
			err := parseRoot(t, d, rss)
			if err != nil {
				return nil, err
			}
			return rss, nil
		}
	}
}

func parseRoot(t xml.StartElement, d *xml.Decoder, rss *RSSFeed) error {
	name := strings.ToLower(t.Name.Local)

	// Parse RSS version from root
	switch name {
	case "rss":
		version := attrValue("version", t.Attr)
		if version != "" {
			rss.Version = version
		}
	case "rdf":
		ns := attrValue("xmlns", t.Attr)
		if ns == "http://channel.netscape.com/rdf/simple/0.9/" {
			rss.Version = "0.9"
		} else if ns == "http://purl.org/rss/1.0/" {
			rss.Version = "1.0"
		}
	default:
		return fmt.Errorf("Invalid root element: %s", name)
	}

	//	for {
	//		token, err := d.Token()
	//
	//		if err != nil || token == nil {
	//			fmt.Println(err)
	//			return nil, err
	//		}
	//
	//		switch t := token.(type) {
	//		case xml.StartElement:
	//			err := parseRoot(t, d, rss)
	//			if err != nil {
	//				return nil, error
	//			}
	//		}
	return nil
}

func attrValue(name string, attrs []xml.Attr) string {
	lname := strings.ToLower(name)
	for _, attr := range attrs {
		if strings.ToLower(attr.Name.Local) == lname {
			return attr.Value
		}
	}
	return ""
}

//func extractNamespaces(attrs []xml.Attr) map[xml.Name]string {
//	ns := make(map[xml.Name]string)
//
//	ns[xml.Name{Space: "", Local: "xml"}] = "http://www.w3.org/XML/1998/namespace"
//
//	for i := range attrs {
//		attr := attrs[i].Name
//		val := attrs[i].Value
//
//		if (attr.Local == "xmlns" && attr.Space == "") || attr.Space == "xmlns" {
//			if attr.Local == "xmlns" && attr.Space == "" && val == "" {
//				delete(ns, attr)
//			} else {
//				ns[attr] = val
//			}
//		} else {
//			attrs = append(attrs, &xmlattr.XMLAttr{Attr: ele.Attr[i], Parent: ch})
//		}
//	}
//}
<commit_msg>Further work on the pull parser<commit_after>package feed

import (
	"encoding/xml"
	"errors"
	"fmt"
	"strings"
	"time"
)

type RSSFeed struct {
	Title               string
	Link                string
	Description         string
	Language            string
	Copyright           string
	ManagingEditor      string
	WebMaster           string
	PubDate             string
	PubDateParsed       time.Time
	LastBuildDate       string
	LastBuildDateParsed time.Time
	Categories          []string
	Generator           string
	Docs                string
	TTL                 string
	Image               RSSImage
	Rating              string
	SkipHours           []string
	SkipDays            []string
	Items               []RSSItem
	Version             string
	Extensions          map[string]interface{}
}

type RSSItem struct {
	Title         string
	Link          string
	Description   string
	Author        string
	Categories    []string
	Comments      string
	Enclosure     RSSEnclosure
	Guid          RSSGuid
	PubDate       string
	PubDateParsed time.Time
	Source        string
	Extensions    map[string]interface{}
}

type RSSImage struct {
	URL    string
	Link   string
	Width  string
	Height string
}

type RSSEnclosure struct {
	URL    string
	Length string
	Type   string
}

type RSSGuid struct {
	Value       string
	IsPermalink string
}

func ParseRSSFeed(feed string) (*RSSFeed, error) {
	rss := &RSSFeed{}

	d := xml.NewDecoder(strings.NewReader(feed))
	d.Strict = false

	for {
		if tok, err = d.Token(); err != nil {
			if err == io.EOF {
				return errors.New("No root node found.")
			}
			return err
		}

		switch tt := tok.(type) {
		case xml.SyntaxError:
			return nil, errors.New(tt.Error())
		case xml.StartElement:
			name := strings.ToLower(tok.Name.Local)
			if name != "rdf" && name != "rss" {
				return nil, fmt.Errorf("Invalid root node: %s", name)
			} else {
				err := parseRoot(t, d, rss)
				if err != nil {
					return nil, err
				}
			}
		case xml.EndElement:
			return rss, nil
		}
	}
}

func parseRoot(t xml.StartElement, d *xml.Decoder, rss *RSSFeed) error {
	rss.Version = parseVersion(t)

	for {
		if tok, err = d.Token(); err != nil {
			if err == io.EOF {
				return nil
			}
			return err
		}

		switch tt := token.(type) {
		case xml.StartElement:
			name := strings.ToLower(tt.Name.Local)
			if name == "channel" {
				parseChannel(tt, d, rss)
			} else if name == "item" {
				parseItem(tt, d, rss)
			} else {
				d.Skip()
			}
		}
	}
}

func parseChannel(t xml.StartElement, d *xml.Decoder, rss *RSSFeed) error {
	for {
		if tok, err = d.Token(); err != nil {
			if err == io.EOF {
				return nil
			}
			return err
		}

		switch tt := token.(type) {
		case xml.StartElement:

		case xml.CharData:

		case xml.EndElement:

		}
	}
}

func parseItem(t xml.StartElement, d *xml.Decoder, rss *RSSFeed) error {
	for {
		token, err := d.Token()

		if err != nil {
			return err
		}

		if token == nil {
			return nil
		}

		switch t := token.(type) {
		case xml.StartElement:
			name := strings.ToLower(t.Name.Local)
			switch name {
			case "channel":
				parseChannel(t, d, rss)
			case "item":
				parseItem(t, d, rss)
			default:
				d.Skip()
			}
		}
	}
	return nil
}

func parseVersion(root xml.StartElement) string {
	var result string
	name := strings.ToLower(root.Name.Local)
	if name == "rss" {
		version := attrValue("version", root.Attr)
		if version != "" {
			result = version
		}
	} else if name == "rdf" {
		ns := attrValue("xmlns", root.Attr)
		if ns == "http://channel.netscape.com/rdf/simple/0.9/" {
			result = "0.9"
		} else if ns == "http://purl.org/rss/1.0/" {
			result = "1.0"
		}
	}
	return result
}

func attrValue(name string, attrs []xml.Attr) string {
	n := strings.ToLower(name)
	for _, attr := range attrs {
		if strings.ToLower(attr.Name.Local) == n {
			return attr.Value
		}
	}
	return ""
}
<|endoftext|>


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

package main

import (
	"bufio"
	"net"
	"strconv"
	"strings"

	log "github.com/Sirupsen/logrus"
	"github.com/osrg/gobgp/packet"
)

const rtrProtocolVersion uint8 = 0

type rtrConn struct {
	conn       *net.TCPConn
	sessionId  uint16
	remoteAddr net.Addr
}

type rtrServer struct {
	connCh     chan *rtrConn
	listenPort int
}

func newRTRServer(port int) *rtrServer {
	s := &rtrServer{
		connCh:     make(chan *rtrConn),
		listenPort: port,
	}
	return s
}

func (s *rtrServer) run() {
	service := ":" + strconv.Itoa(s.listenPort)
	addr, _ := net.ResolveTCPAddr("tcp", service)

	l, err := net.ListenTCP("tcp", addr)
	checkError(err)

	for i := 0; ; {
		conn, err := l.AcceptTCP()
		if err != nil {
			continue
		}
		i++
		c := &rtrConn{
			conn:       conn,
			sessionId:  uint16(i),
			remoteAddr: conn.RemoteAddr(),
		}
		s.connCh <- c
	}
}

func (rtr *rtrConn) sendDeltaPrefixes(r *ResourceManager, peerSN uint32) error {
	var counter uint32
	for _, rf := range []bgp.RouteFamily{bgp.RF_IPv4_UC, bgp.RF_IPv6_UC} {
		counter = 0
		for _, v := range r.ToBeAdded(rf, peerSN) {
			if err := rtr.sendPDU(bgp.NewRTRIPPrefix(v.Prefix, v.PrefixLen, v.MaxLen, v.AS, bgp.ANNOUNCEMENT)); err != nil {
				return err
			}
			counter++
			log.Debugf("Sent %s Prefix PDU to %v (Prefix: %v/%v, Maxlen: %v, AS: %v, flags: ANNOUNCE)", RFToIPVer(rf), rtr.remoteAddr, v.Prefix, v.PrefixLen, v.MaxLen, v.AS)
		}
		if !commandOpts.Debug && counter != 0 {
			log.Infof("Sent %s Prefix PDU(s) to %v (%d ROA(s), flags: ANNOUNCE)", RFToIPVer(rf), rtr.remoteAddr, counter)
		}

		counter = 0
		for _, v := range r.ToBeDeleted(rf, peerSN) {
			if err := rtr.sendPDU(bgp.NewRTRIPPrefix(v.Prefix, v.PrefixLen, v.MaxLen, v.AS, bgp.WITHDRAWAL)); err != nil {
				return err
			}
			counter++
			log.Debugf("Sent %s PDU to %v (Prefix: %v/%v, Maxlen: %v, AS: %v, flags: WITHDRAW)", RFToIPVer(rf), rtr.remoteAddr, v.Prefix, v.PrefixLen, v.MaxLen, v.AS)
		}
		if !commandOpts.Debug && counter != 0 {
			log.Infof("Sent %s Prefix PDU(s) to %v (%d ROA(s), flags: WITHDRAW)", RFToIPVer(rf), rtr.remoteAddr, counter)
		}
	}
	return nil
}

func (rtr *rtrConn) sendAllPrefixes(r *ResourceManager) error {
	var counter uint32
	for _, rf := range []bgp.RouteFamily{bgp.RF_IPv4_UC, bgp.RF_IPv6_UC} {
		counter = 0
		for _, v := range r.CurrentList(rf) {
			if err := rtr.sendPDU(bgp.NewRTRIPPrefix(v.Prefix, v.PrefixLen, v.MaxLen, v.AS, bgp.ANNOUNCEMENT)); err != nil {
				return err
			}
			counter++
			log.Debugf("Sent %s Prefix PDU to %v (Prefix: %v/%v, Maxlen: %v, AS: %v, flags: ANNOUNCE)", RFToIPVer(rf), rtr.remoteAddr, v.Prefix, v.PrefixLen, v.MaxLen, v.AS)
		}
		if !commandOpts.Debug && counter != 0 {
			log.Infof("Sent %s Prefix PDU(s) to %v (%d ROA(s), flags: ANNOUNCE)", RFToIPVer(rf), rtr.remoteAddr, counter)
		}
	}
	return nil
}

func (rtr *rtrConn) sendPDU(pdu bgp.RTRMessage) error {
	data, _ := pdu.Serialize()
	_, err := rtr.conn.Write(data)
	if err != nil {
		return err
	}
	return nil
}

func (rtr *rtrConn) startOrRestart(r *ResourceManager) error {
	t := r.BeginTransaction()
	defer t.EndTransaction()
	err := rtr.sendAllPrefixes(t)
	if err == nil {
		if err := rtr.sendPDU(bgp.NewRTREndOfData(rtr.sessionId, t.CurrentSerial())); err == nil {
			log.Infof("Sent End of Data PDU to %v (ID: %v, SN: %v)", rtr.remoteAddr, rtr.sessionId, t.CurrentSerial())
			return nil
		}
	}
	return err
}

func (rtr *rtrConn) typicalExchange(r *ResourceManager, peerSN uint32) error {
	t := r.BeginTransaction()
	defer t.EndTransaction()
	err := rtr.sendPDU(bgp.NewRTRCacheResponse(rtr.sessionId))
	if err == nil {
		log.Infof("Sent Cache Response PDU to %v (ID: %v)", rtr.remoteAddr, rtr.sessionId)
		err = rtr.sendDeltaPrefixes(t, peerSN)
		if err == nil {
			err = rtr.sendPDU(bgp.NewRTREndOfData(rtr.sessionId, t.CurrentSerial()))
			if err == nil {
				log.Infof("Sent End of Data PDU to %v (ID: %v, SN: %v)", rtr.remoteAddr, rtr.sessionId, t.CurrentSerial())
				return nil
			}
		}
	}
	return err
}

func (rtr *rtrConn) noIncrementalUpdateAvailable() error {
	err := rtr.sendPDU(bgp.NewRTRCacheReset())
	if err == nil {
		log.Infof("Sent Cache Reset PDU to %v", rtr.remoteAddr)
		return nil
	}
	return err
}

func (rtr *rtrConn) cacheHasNoDataAvailable() error {
	err := rtr.sendPDU(bgp.NewRTRErrorReport(bgp.NO_DATA_AVAILABLE, nil, nil))
	if err == nil {
		return nil
	}
	return err
}

func RFToIPVer(rf bgp.RouteFamily) string {
	return strings.Split(rf.String(), "_")[1]
}

type errMsg struct {
	code uint16
	data []byte
}

func handleRTR(rtr *rtrConn, r *ResourceManager) {
	bcastReceiver := r.serialNotify.Join()
	scanner := bufio.NewScanner(bufio.NewReader(rtr.conn))
	scanner.Split(bgp.SplitRTR)

	msgCh := make(chan bgp.RTRMessage)
	errCh := make(chan *errMsg)
	go func() {
		defer func() {
			log.Infof("Connection to %v was closed. (ID: %v)", rtr.remoteAddr, rtr.sessionId)
			rtr.conn.Close()
		}()

		for scanner.Scan() {
			buf := scanner.Bytes()
			if buf[0] != rtrProtocolVersion {
				errCh <- &errMsg{code: bgp.UNSUPPORTED_PROTOCOL_VERSION, data: buf}
			}
			m, err := bgp.ParseRTR(buf)
			if err != nil {
				errCh <- &errMsg{code: bgp.INVALID_REQUEST, data: buf}
			}
			msgCh <- m
		}
	}()

LOOP:
	for {
		select {
		case <-bcastReceiver.In:
			t := r.BeginTransaction()
			if err := rtr.sendPDU(bgp.NewRTRSerialNotify(rtr.sessionId, t.CurrentSerial())); err != nil {
				break LOOP
			}
			log.Infof("Sent Serial Notify PDU to %v (ID: %v, SN: %v)", rtr.remoteAddr, rtr.sessionId, t.CurrentSerial())
			t.EndTransaction()
		case msg := <-errCh:
			rtr.sendPDU(bgp.NewRTRErrorReport(msg.code, msg.data, nil))
			log.Infof("Sent Error Report PDU to %v (ID: %v, ErrorCode: %v)", rtr.remoteAddr, rtr.sessionId, msg.code)
			return
		case m := <-msgCh:
			switch msg := m.(type) {
			case *bgp.RTRSerialQuery:
				peerSN := msg.SerialNumber
				log.Infof("Received Serial Query PDU from %v (ID: %v, SN: %d)", rtr.remoteAddr, msg.SessionID, peerSN)
				if r.HasKey(peerSN) {
					if err := rtr.typicalExchange(r, peerSN); err == nil {
						continue
					}
				}
				if err := rtr.noIncrementalUpdateAvailable(); err == nil {
					continue
				}
				break LOOP
			case *bgp.RTRResetQuery:
				log.Infof("Received Reset Query PDU from %v", rtr.remoteAddr)
				if r == nil {
					if err := rtr.cacheHasNoDataAvailable(); err == nil {
						continue
					}
				}
				if err := rtr.startOrRestart(r); err == nil {
					continue
				}
				break LOOP
			case *bgp.RTRErrorReport:
				log.Warnf("Received Error Report PDU from %v (%#v)", rtr.remoteAddr, msg)
				return
			default:
				pdu, _ := msg.Serialize()
				log.Warnf("Received unsupported PDU (type %d) from %v (%#v)", pdu[1], rtr.remoteAddr, msg)
				rtr.sendPDU(bgp.NewRTRErrorReport(bgp.UNSUPPORTED_PDU_TYPE, pdu, nil))
				return
			}
		}
	}
	rtr.sendPDU(bgp.NewRTRErrorReport(bgp.INTERNAL_ERROR, nil, nil))
	return
}
<commit_msg>Fix missing cache response<commit_after>// Copyright (C) 2015 Eiichiro Watanabe
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//    http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
// implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package main

import (
	"bufio"
	"net"
	"strconv"
	"strings"

	log "github.com/Sirupsen/logrus"
	"github.com/osrg/gobgp/packet"
)

const rtrProtocolVersion uint8 = 0

type rtrConn struct {
	conn       *net.TCPConn
	sessionId  uint16
	remoteAddr net.Addr
}

type rtrServer struct {
	connCh     chan *rtrConn
	listenPort int
}

func newRTRServer(port int) *rtrServer {
	s := &rtrServer{
		connCh:     make(chan *rtrConn),
		listenPort: port,
	}
	return s
}

func (s *rtrServer) run() {
	service := ":" + strconv.Itoa(s.listenPort)
	addr, _ := net.ResolveTCPAddr("tcp", service)

	l, err := net.ListenTCP("tcp", addr)
	checkError(err)

	for i := 0; ; {
		conn, err := l.AcceptTCP()
		if err != nil {
			continue
		}
		i++
		c := &rtrConn{
			conn:       conn,
			sessionId:  uint16(i),
			remoteAddr: conn.RemoteAddr(),
		}
		s.connCh <- c
	}
}

func (rtr *rtrConn) sendDeltaPrefixes(r *ResourceManager, peerSN uint32) error {
	var counter uint32
	for _, rf := range []bgp.RouteFamily{bgp.RF_IPv4_UC, bgp.RF_IPv6_UC} {
		counter = 0
		for _, v := range r.ToBeAdded(rf, peerSN) {
			if err := rtr.sendPDU(bgp.NewRTRIPPrefix(v.Prefix, v.PrefixLen, v.MaxLen, v.AS, bgp.ANNOUNCEMENT)); err != nil {
				return err
			}
			counter++
			log.Debugf("Sent %s Prefix PDU to %v (Prefix: %v/%v, Maxlen: %v, AS: %v, flags: ANNOUNCE)", RFToIPVer(rf), rtr.remoteAddr, v.Prefix, v.PrefixLen, v.MaxLen, v.AS)
		}
		if !commandOpts.Debug && counter != 0 {
			log.Infof("Sent %s Prefix PDU(s) to %v (%d ROA(s), flags: ANNOUNCE)", RFToIPVer(rf), rtr.remoteAddr, counter)
		}

		counter = 0
		for _, v := range r.ToBeDeleted(rf, peerSN) {
			if err := rtr.sendPDU(bgp.NewRTRIPPrefix(v.Prefix, v.PrefixLen, v.MaxLen, v.AS, bgp.WITHDRAWAL)); err != nil {
				return err
			}
			counter++
			log.Debugf("Sent %s PDU to %v (Prefix: %v/%v, Maxlen: %v, AS: %v, flags: WITHDRAW)", RFToIPVer(rf), rtr.remoteAddr, v.Prefix, v.PrefixLen, v.MaxLen, v.AS)
		}
		if !commandOpts.Debug && counter != 0 {
			log.Infof("Sent %s Prefix PDU(s) to %v (%d ROA(s), flags: WITHDRAW)", RFToIPVer(rf), rtr.remoteAddr, counter)
		}
	}
	return nil
}

func (rtr *rtrConn) sendAllPrefixes(r *ResourceManager) error {
	var counter uint32
	for _, rf := range []bgp.RouteFamily{bgp.RF_IPv4_UC, bgp.RF_IPv6_UC} {
		counter = 0
		for _, v := range r.CurrentList(rf) {
			if err := rtr.sendPDU(bgp.NewRTRIPPrefix(v.Prefix, v.PrefixLen, v.MaxLen, v.AS, bgp.ANNOUNCEMENT)); err != nil {
				return err
			}
			counter++
			log.Debugf("Sent %s Prefix PDU to %v (Prefix: %v/%v, Maxlen: %v, AS: %v, flags: ANNOUNCE)", RFToIPVer(rf), rtr.remoteAddr, v.Prefix, v.PrefixLen, v.MaxLen, v.AS)
		}
		if !commandOpts.Debug && counter != 0 {
			log.Infof("Sent %s Prefix PDU(s) to %v (%d ROA(s), flags: ANNOUNCE)", RFToIPVer(rf), rtr.remoteAddr, counter)
		}
	}
	return nil
}

func (rtr *rtrConn) sendPDU(pdu bgp.RTRMessage) error {
	data, _ := pdu.Serialize()
	_, err := rtr.conn.Write(data)
	if err != nil {
		return err
	}
	return nil
}

func (rtr *rtrConn) startOrRestart(r *ResourceManager) error {
	t := r.BeginTransaction()
	defer t.EndTransaction()
	err := rtr.sendPDU(bgp.NewRTRCacheResponse(rtr.sessionId))
	if err == nil {
		log.Infof("Sent Cache Response PDU to %v (ID: %v)", rtr.remoteAddr, rtr.sessionId)
		err := rtr.sendAllPrefixes(t)
		if err == nil {
			if err := rtr.sendPDU(bgp.NewRTREndOfData(rtr.sessionId, t.CurrentSerial())); err == nil {
				log.Infof("Sent End of Data PDU to %v (ID: %v, SN: %v)", rtr.remoteAddr, rtr.sessionId, t.CurrentSerial())
				return nil
			}
		}
	}
	return err
}

func (rtr *rtrConn) typicalExchange(r *ResourceManager, peerSN uint32) error {
	t := r.BeginTransaction()
	defer t.EndTransaction()
	err := rtr.sendPDU(bgp.NewRTRCacheResponse(rtr.sessionId))
	if err == nil {
		log.Infof("Sent Cache Response PDU to %v (ID: %v)", rtr.remoteAddr, rtr.sessionId)
		err = rtr.sendDeltaPrefixes(t, peerSN)
		if err == nil {
			err = rtr.sendPDU(bgp.NewRTREndOfData(rtr.sessionId, t.CurrentSerial()))
			if err == nil {
				log.Infof("Sent End of Data PDU to %v (ID: %v, SN: %v)", rtr.remoteAddr, rtr.sessionId, t.CurrentSerial())
				return nil
			}
		}
	}
	return err
}

func (rtr *rtrConn) noIncrementalUpdateAvailable() error {
	err := rtr.sendPDU(bgp.NewRTRCacheReset())
	if err == nil {
		log.Infof("Sent Cache Reset PDU to %v", rtr.remoteAddr)
		return nil
	}
	return err
}

func (rtr *rtrConn) cacheHasNoDataAvailable() error {
	err := rtr.sendPDU(bgp.NewRTRErrorReport(bgp.NO_DATA_AVAILABLE, nil, nil))
	if err == nil {
		return nil
	}
	return err
}

func RFToIPVer(rf bgp.RouteFamily) string {
	return strings.Split(rf.String(), "_")[1]
}

type errMsg struct {
	code uint16
	data []byte
}

func handleRTR(rtr *rtrConn, r *ResourceManager) {
	bcastReceiver := r.serialNotify.Join()
	scanner := bufio.NewScanner(bufio.NewReader(rtr.conn))
	scanner.Split(bgp.SplitRTR)

	msgCh := make(chan bgp.RTRMessage)
	errCh := make(chan *errMsg)
	go func() {
		defer func() {
			log.Infof("Connection to %v was closed. (ID: %v)", rtr.remoteAddr, rtr.sessionId)
			rtr.conn.Close()
		}()

		for scanner.Scan() {
			buf := scanner.Bytes()
			if buf[0] != rtrProtocolVersion {
				errCh <- &errMsg{code: bgp.UNSUPPORTED_PROTOCOL_VERSION, data: buf}
			}
			m, err := bgp.ParseRTR(buf)
			if err != nil {
				errCh <- &errMsg{code: bgp.INVALID_REQUEST, data: buf}
			}
			msgCh <- m
		}
	}()

LOOP:
	for {
		select {
		case <-bcastReceiver.In:
			t := r.BeginTransaction()
			if err := rtr.sendPDU(bgp.NewRTRSerialNotify(rtr.sessionId, t.CurrentSerial())); err != nil {
				break LOOP
			}
			log.Infof("Sent Serial Notify PDU to %v (ID: %v, SN: %v)", rtr.remoteAddr, rtr.sessionId, t.CurrentSerial())
			t.EndTransaction()
		case msg := <-errCh:
			rtr.sendPDU(bgp.NewRTRErrorReport(msg.code, msg.data, nil))
			log.Infof("Sent Error Report PDU to %v (ID: %v, ErrorCode: %v)", rtr.remoteAddr, rtr.sessionId, msg.code)
			return
		case m := <-msgCh:
			switch msg := m.(type) {
			case *bgp.RTRSerialQuery:
				peerSN := msg.SerialNumber
				log.Infof("Received Serial Query PDU from %v (ID: %v, SN: %d)", rtr.remoteAddr, msg.SessionID, peerSN)
				if r.HasKey(peerSN) {
					if err := rtr.typicalExchange(r, peerSN); err == nil {
						continue
					}
				}
				if err := rtr.noIncrementalUpdateAvailable(); err == nil {
					continue
				}
				break LOOP
			case *bgp.RTRResetQuery:
				log.Infof("Received Reset Query PDU from %v", rtr.remoteAddr)
				if r == nil {
					if err := rtr.cacheHasNoDataAvailable(); err == nil {
						continue
					}
				}
				if err := rtr.startOrRestart(r); err == nil {
					continue
				}
				break LOOP
			case *bgp.RTRErrorReport:
				log.Warnf("Received Error Report PDU from %v (%#v)", rtr.remoteAddr, msg)
				return
			default:
				pdu, _ := msg.Serialize()
				log.Warnf("Received unsupported PDU (type %d) from %v (%#v)", pdu[1], rtr.remoteAddr, msg)
				rtr.sendPDU(bgp.NewRTRErrorReport(bgp.UNSUPPORTED_PDU_TYPE, pdu, nil))
				return
			}
		}
	}
	rtr.sendPDU(bgp.NewRTRErrorReport(bgp.INTERNAL_ERROR, nil, nil))
	return
}
<|endoftext|>


<commit_before>package main

/*
loadTinzenite loads an existing Tinzenite directory and runs it.
*/import (
	"fmt"
	"github.com/tinzenite/bootstrap"
	"github.com/tinzenite/core"
	"github.com/tinzenite/shared"
	"log"
	"os"
	"os/signal"
	"time"
)

func bootstrapTinzenite(path string) {
	var boot *bootstrap.Bootstrap
	var err error
	done := make(chan bool)
	if shared.IsTinzenite(path) {
		boot, err = bootstrap.Load(path, func() {
			done <- true
		})
		if err != nil {
			logMain("Bootstrap load error:", err.Error())
			return
		}
	} else {
		peerName := getString("Enter the peer name for this Tinzenite directory:")
		boot, err = bootstrap.Create(path, peerName, func() {
			done <- true
		})
		if err != nil {
			logMain("Bootstrap create error:", err.Error())
			return
		}
		// connect to:
		address := getString("Please enter the address of the peer to connect to:")
		err = boot.Start(address)
		if err != nil {
			logMain("Bootstrap start error:", err.Error())
			// return because we don't want to store a faulty bootstrap
			return
		}
		err = boot.Store()
		if err != nil {
			logMain("Bootstrap store error:", err.Error())
		}
	}
	// print information
	address, _ := boot.Address()
	fmt.Printf("Bootstrapping.\nID: %s\n", address)
	// wait for successful bootstrap
	<-done
	log.Println("Closing Bootstrap.")
	// this is required before closing boot because ToxCore may still need to
	// notify the other client that the file transfers are complete - this can
	// take a few iterations, so we delay for a second to give it time to do that.
	<-time.Tick(1 * time.Second)
	// manually close boot if we're done! It won't close itself!
	boot.Close()
	// continue to executing the directory
	fmt.Println("Bootstrapping was successful. Loading Tinzenite.")
	loadTinzenite(path)
}

func createTinzenite(path string) {
	if shared.IsTinzenite(path) {
		logMain("Directory is already a valid Tinzenite directory!")
		return
	}
	// get options
	peerName := getString("Enter the peer name for this Tinzenite directory:")
	userName := getString("Enter your username:")
	password := getString("Enter a password for this Tinzenite network:")
	relPath := shared.CreatePathRoot(path)
	tinzenite, err := core.CreateTinzenite(relPath.LastElement(), relPath.FullPath(), peerName, userName, password)
	if err != nil {
		logMain("Creation error:", err.Error())
		return
	}
	err = tinzenite.SyncLocal()
	if err != nil {
		logMain("Initial model sync error:", err.Error())
	}
	// run tinzenite until killed
	runTinzenite(tinzenite)
}

func loadTinzenite(path string) {
	if !shared.IsTinzenite(path) {
		logMain("Directory is not a valid Tinzenite directory!")
		return
	}
	password := getString("Please enter the directory password:")
	tinzenite, err := core.LoadTinzenite(path, password)
	if err != nil {
		// TODO catch wrong password and allow retry
		logMain("Loading error:", err.Error())
		return
	}
	err = tinzenite.SyncLocal()
	if err != nil {
		logMain("Initial model sync error:", err.Error())
	}
	// run tinzenite until killed
	runTinzenite(tinzenite)
}

/*
runTinzenite runs the given Tinzenite instance.
*/
func runTinzenite(t *core.Tinzenite) {
	// do this here so that it is guaranteed to be set
	t.RegisterPeerValidation(allowPeer)
	// print important info
	address, _ := t.Address()
	fmt.Printf("Running peer <%s>.\nID: %s\n", t.Name(), address)
	// run update and sync in intervalls
	// var counter int
	c := make(chan os.Signal, 1)
	signal.Notify(c, os.Interrupt)
	for {
		select {
		case <-time.Tick(time.Duration(10) * time.Second):
			log.Println("DEBUG: Model sync ---------------------------")
			err := t.SyncRemote()
			if err != nil {
				logMain("SyncRemote error:", err.Error())
			}
			/*
				if counter >= 5 {
					// TODO remove once Merge bug is fixed
					log.Println("DEBUG: Model sync ---------------------------")
					counter = 0
					err := t.SyncRemote()
					if err != nil {
						logMain("SyncRemote error:", err.Error())
					}
					continue
				}
				// log.Println("DEBUG: Update")
				counter++
				err := t.SyncLocal()
				if err != nil {
					logMain("SyncLocal error:", err.Error())
				}
			*/
		case <-c:
			// on interrupt close tinzenite
			t.Close()
			return
		} // select
	} // for
}

/*
allowPeer asks the user whether to accept the given peer.
*/
func allowPeer(address string, wantsTrust bool) bool {
	// TODO actually ask! NOTE: shouldn't block... how? Call silent add friend on success?
	log.Println("TODO: Actually ask, for now accepting everything!", address)
	return true
}
<commit_msg>changed ticking back to sync & update version<commit_after>package main

/*
loadTinzenite loads an existing Tinzenite directory and runs it.
*/import (
	"fmt"
	"github.com/tinzenite/bootstrap"
	"github.com/tinzenite/core"
	"github.com/tinzenite/shared"
	"log"
	"os"
	"os/signal"
	"time"
)

func bootstrapTinzenite(path string) {
	var boot *bootstrap.Bootstrap
	var err error
	done := make(chan bool)
	if shared.IsTinzenite(path) {
		boot, err = bootstrap.Load(path, func() {
			done <- true
		})
		if err != nil {
			logMain("Bootstrap load error:", err.Error())
			return
		}
	} else {
		peerName := getString("Enter the peer name for this Tinzenite directory:")
		boot, err = bootstrap.Create(path, peerName, func() {
			done <- true
		})
		if err != nil {
			logMain("Bootstrap create error:", err.Error())
			return
		}
		// connect to:
		address := getString("Please enter the address of the peer to connect to:")
		err = boot.Start(address)
		if err != nil {
			logMain("Bootstrap start error:", err.Error())
			// return because we don't want to store a faulty bootstrap
			return
		}
		err = boot.Store()
		if err != nil {
			logMain("Bootstrap store error:", err.Error())
		}
	}
	// print information
	address, _ := boot.Address()
	fmt.Printf("Bootstrapping.\nID: %s\n", address)
	// wait for successful bootstrap
	<-done
	log.Println("Closing Bootstrap.")
	// this is required before closing boot because ToxCore may still need to
	// notify the other client that the file transfers are complete - this can
	// take a few iterations, so we delay for a second to give it time to do that.
	<-time.Tick(1 * time.Second)
	// manually close boot if we're done! It won't close itself!
	boot.Close()
	// continue to executing the directory
	fmt.Println("Bootstrapping was successful. Loading Tinzenite.")
	loadTinzenite(path)
}

func createTinzenite(path string) {
	if shared.IsTinzenite(path) {
		logMain("Directory is already a valid Tinzenite directory!")
		return
	}
	// get options
	peerName := getString("Enter the peer name for this Tinzenite directory:")
	userName := getString("Enter your username:")
	password := getString("Enter a password for this Tinzenite network:")
	relPath := shared.CreatePathRoot(path)
	tinzenite, err := core.CreateTinzenite(relPath.LastElement(), relPath.FullPath(), peerName, userName, password)
	if err != nil {
		logMain("Creation error:", err.Error())
		return
	}
	err = tinzenite.SyncLocal()
	if err != nil {
		logMain("Initial model sync error:", err.Error())
	}
	// run tinzenite until killed
	runTinzenite(tinzenite)
}

func loadTinzenite(path string) {
	if !shared.IsTinzenite(path) {
		logMain("Directory is not a valid Tinzenite directory!")
		return
	}
	password := getString("Please enter the directory password:")
	tinzenite, err := core.LoadTinzenite(path, password)
	if err != nil {
		// TODO catch wrong password and allow retry
		logMain("Loading error:", err.Error())
		return
	}
	err = tinzenite.SyncLocal()
	if err != nil {
		logMain("Initial model sync error:", err.Error())
	}
	// run tinzenite until killed
	runTinzenite(tinzenite)
}

/*
runTinzenite runs the given Tinzenite instance.
*/
func runTinzenite(t *core.Tinzenite) {
	// do this here so that it is guaranteed to be set
	t.RegisterPeerValidation(allowPeer)
	// print important info
	address, _ := t.Address()
	fmt.Printf("Running peer <%s>.\nID: %s\n", t.Name(), address)
	// run update and sync in intervalls
	var counter int
	// only build this once instead of every time
	tickSpan := time.Duration(10) * time.Second
	// prepare quitting via ctrl-c
	c := make(chan os.Signal, 1)
	signal.Notify(c, os.Interrupt)
	// loop until close
	for {
		select {
		case <-time.Tick(tickSpan):
			if counter >= 5 {
				// TODO remove once Merge bug is fixed
				log.Println("DEBUG: Model sync ---------------------------")
				counter = 0
				err := t.SyncRemote()
				if err != nil {
					logMain("SyncRemote error:", err.Error())
				}
				continue
			}
			// log.Println("DEBUG: Update")
			counter++
			err := t.SyncLocal()
			if err != nil {
				logMain("SyncLocal error:", err.Error())
			}
		case <-c:
			// on interrupt close tinzenite
			t.Close()
			return
		} // select
	} // for
}

/*
allowPeer asks the user whether to accept the given peer.
*/
func allowPeer(address string, wantsTrust bool) bool {
	// TODO actually ask! NOTE: shouldn't block... how? Call silent add friend on success?
	log.Println("TODO: Actually ask, for now accepting everything!", address)
	return true
}
<|endoftext|>