<commit_before>/* Copyright (C) 2013 CompleteDB LLC.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with PubSubSQL.  If not, see <http://www.gnu.org/licenses/>.
 */

package pubsubsql

import "strconv"

type responseStatusType int8

const (
	responseStatusOk  responseStatusType = iota // ok.
	responseStatusErr                           // error.
)

// response
type response interface {
	getResponseStatus() responseStatusType
	toNetworkReadyJSON() ([]byte, bool)
	setRequestId(requestId uint32)
}

type requestIdResponse struct {
	response
	requestId uint32
}

func (this *requestIdResponse) setRequestId(requestId uint32) {
	this.requestId = requestId
}

// json helper functions
func ok(builder *JSONBuilder) {
	builder.nameValue("status", "ok")
}

func id(builder *JSONBuilder, id string) {
	builder.nameValue("id", id)
}

func action(builder *JSONBuilder, action string) {
	builder.nameValue("action", action)
}

// errorResponse
type errorResponse struct {
	requestIdResponse
	msg string
}

func newErrorResponse(msg string) *errorResponse {
	return &errorResponse{
		msg: msg,
	}
}

func (this *errorResponse) getResponsStatus() responseStatusType {
	return responseStatusErr
}

func (this *errorResponse) toNetworkReadyJSON() ([]byte, bool) {
	builder := networkReadyJSONBuilder()
	builder.beginObject()
	builder.nameValue("status", "err")
	builder.valueSeparator()
	builder.nameValue("msg", this.msg)
	builder.endObject()
	return builder.getNetworkBytes(this.requestId), false
}

// okResponse
type okResponse struct {
	requestIdResponse
	action string
}

func newOkResponse(action string) *okResponse {
	return &okResponse{action: action}
}

func (this *okResponse) getResponsStatus() responseStatusType {
	return responseStatusOk
}

func (this *okResponse) toNetworkReadyJSON() ([]byte, bool) {
	builder := networkReadyJSONBuilder()
	builder.beginObject()
	ok(builder)
	builder.valueSeparator()
	action(builder, this.action)
	builder.endObject()
	return builder.getNetworkBytes(this.requestId), false
}

// cmdStatusResponse
type cmdStatusResponse struct {
	requestIdResponse
	connections int
}

func newCmdStatusResponse(connections int) *cmdStatusResponse {
	return &cmdStatusResponse{
		connections: connections,
	}
}

func (this *cmdStatusResponse) toNetworkReadyJSON() ([]byte, bool) {
	builder := networkReadyJSONBuilder()
	builder.beginObject()
	ok(builder)
	builder.valueSeparator()
	action(builder, "status")
	builder.valueSeparator()
	builder.nameIntValue("connections", this.connections)
	builder.endObject()
	return builder.getNetworkBytes(this.requestId), false
}

// sqlInsertResponse is a response for sql insert statement
type sqlInsertResponse struct {
	requestIdResponse
	id string
}

func newSqlInsertResponse(id string) *sqlInsertResponse {
	return &sqlInsertResponse{
		id: id,
	}
}

func (this *sqlInsertResponse) getResponsStatus() responseStatusType {
	return responseStatusOk
}

func (this *sqlInsertResponse) toNetworkReadyJSON() ([]byte, bool) {
	builder := networkReadyJSONBuilder()
	builder.beginObject()
	ok(builder)
	builder.valueSeparator()
	action(builder, "insert")
	builder.valueSeparator()
	id(builder, this.id)
	builder.endObject()
	return builder.getNetworkBytes(this.requestId), false
}

// sqlSelectResponse is a response for sql select statement
type sqlSelectResponse struct {
	requestIdResponse
	columns []*column
	records []*record
	batch   int
}

func row(builder *JSONBuilder, columns []*column, rec *record) {
	builder.beginObject()
	// columns and values
	for colIndex, col := range columns {
		if colIndex != 0 {
			builder.valueSeparator()
		}
		builder.nameValue(col.name, rec.getValue(colIndex))
	}
	builder.endObject()
}

func (this *sqlSelectResponse) data(builder *JSONBuilder) bool {
	more := len(this.records) > config.DATA_BATCH_SIZE
	records := this.records
	if more {
		records = this.records[0:config.DATA_BATCH_SIZE]
		this.records = this.records[config.DATA_BATCH_SIZE:]
		//
		this.batch++
		builder.nameIntValue("batch", this.batch)
		builder.valueSeparator()
	}
	builder.nameIntValue("rows", len(this.records))
	builder.valueSeparator()
	builder.string("data")
	builder.nameSeparator()
	builder.beginArray()
	for recIndex, rec := range records {
		// another row
		if recIndex != 0 {
			builder.objectSeparator()
		}
		row(builder, this.columns, rec)
	}
	builder.endArray()
	return more
}

func (this *sqlSelectResponse) toNetworkReadyJSON() ([]byte, bool) {
	builder := networkReadyJSONBuilder()
	builder.beginObject()
	ok(builder)
	builder.valueSeparator()
	action(builder, "select")
	builder.valueSeparator()
	more := this.data(builder)
	builder.endObject()
	return builder.getNetworkBytes(this.requestId), more
}

func (this *sqlSelectResponse) copyRecordData(source *record) {
	l := len(this.columns)
	dest := &record{
		values: make([]string, l, l),
	}
	for idx, col := range this.columns {
		dest.setValue(idx, source.getValue(col.ordinal))
	}
	addRecordToSlice(&this.records, dest)
}

// sqlDeleteResponse
type sqlDeleteResponse struct {
	requestIdResponse
	deleted int
}

func (this *sqlDeleteResponse) toNetworkReadyJSON() ([]byte, bool) {
	builder := networkReadyJSONBuilder()
	builder.beginObject()
	ok(builder)
	builder.valueSeparator()
	action(builder, "delete")
	builder.valueSeparator()
	builder.nameIntValue("rows", this.deleted)
	builder.endObject()
	return builder.getNetworkBytes(this.requestId), false
}

// sqlUpdateResponse
type sqlUpdateResponse struct {
	requestIdResponse
	updated int
}

func (this *sqlUpdateResponse) toNetworkReadyJSON() ([]byte, bool) {
	builder := networkReadyJSONBuilder()
	builder.beginObject()
	ok(builder)
	builder.valueSeparator()
	action(builder, "update")
	builder.valueSeparator()
	builder.nameIntValue("rows", this.updated)
	builder.endObject()
	return builder.getNetworkBytes(this.requestId), false
}

// sqlSubscribeResponse
type sqlSubscribeResponse struct {
	requestIdResponse
	pubsubid uint64
}

func (this *sqlSubscribeResponse) toNetworkReadyJSON() ([]byte, bool) {
	builder := networkReadyJSONBuilder()
	builder.beginObject()
	ok(builder)
	builder.valueSeparator()
	action(builder, "subscribe")
	builder.valueSeparator()
	builder.nameValue("pubsubid", strconv.FormatUint(this.pubsubid, 10))
	builder.endObject()
	return builder.getNetworkBytes(this.requestId), false
}

func newSubscribeResponse(sub *subscription) response {
	return &sqlSubscribeResponse{
		pubsubid: sub.id,
	}
}

// sqlActionDataResponse
type sqlActionDataResponse struct {
	sqlSelectResponse
	pubsubid uint64
}

func (this *sqlActionDataResponse) toNetworkReadyJSONHelper(act string) ([]byte, bool) {
	builder := networkReadyJSONBuilder()
	builder.beginObject()
	ok(builder)
	builder.valueSeparator()
	action(builder, act)
	builder.valueSeparator()
	builder.nameValue("pubsubid", strconv.FormatUint(this.pubsubid, 10))
	builder.valueSeparator()
	more := this.data(builder)
	builder.endObject()
	return builder.getNetworkBytes(0), more
}

// sqlActionAddResponse
type sqlActionAddResponse struct {
	sqlActionDataResponse
}

func (this *sqlActionAddResponse) toNetworkReadyJSON() ([]byte, bool) {
	return this.toNetworkReadyJSONHelper("add")
}

// sqlActionInsertResponse
type sqlActionInsertResponse struct {
	sqlActionDataResponse
}

func (this *sqlActionInsertResponse) toNetworkReadyJSON() ([]byte, bool) {
	return this.toNetworkReadyJSONHelper("insert")
}

// sqlActonDeleteResponse
type sqlActionDeleteResponse struct {
	response
	id       string
	pubsubid uint64
}

func (this *sqlActionDeleteResponse) setRequestId(requestId uint32) {

}

func (this *sqlActionDeleteResponse) toNetworkReadyJSON() ([]byte, bool) {
	builder := networkReadyJSONBuilder()
	builder.beginObject()
	ok(builder)
	builder.valueSeparator()
	action(builder, "delete")
	builder.valueSeparator()
	builder.nameValue("pubsubid", strconv.FormatUint(this.pubsubid, 10))
	builder.valueSeparator()
	builder.nameValue("id", this.id)
	builder.endObject()
	return builder.getNetworkBytes(0), false
}

// sqlActionRemoveResponse
type sqlActionRemoveResponse struct {
	response
	id       string
	pubsubid uint64
}

func (this *sqlActionRemoveResponse) setRequestId(requestId uint32) {

}

func (this *sqlActionRemoveResponse) toNetworkReadyJSON() ([]byte, bool) {
	builder := networkReadyJSONBuilder()
	builder.beginObject()
	ok(builder)
	builder.valueSeparator()
	action(builder, "remove")
	builder.valueSeparator()
	builder.nameValue("pubsubid", strconv.FormatUint(this.pubsubid, 10))
	builder.valueSeparator()
	builder.nameValue("id", this.id)
	builder.endObject()
	return builder.getNetworkBytes(0), false
}

// sqlActionUpdateResponse
type sqlActionUpdateResponse struct {
	response
	pubsubid uint64
	cols     []*column
	rec      *record
}

func (this *sqlActionUpdateResponse) setRequestId(requestId uint32) {

}

func (this *sqlActionUpdateResponse) toNetworkReadyJSON() ([]byte, bool) {
	builder := networkReadyJSONBuilder()
	builder.beginObject()
	ok(builder)
	builder.valueSeparator()
	action(builder, "update")
	builder.valueSeparator()
	builder.nameValue("pubsubid", strconv.FormatUint(this.pubsubid, 10))
	builder.valueSeparator()

	builder.string("data")
	builder.nameSeparator()
	builder.beginArray()
	row(builder, this.cols, this.rec)
	builder.endArray()

	builder.endObject()
	return builder.getNetworkBytes(0), false
}

func newSqlActionUpdateResponse(pubsubid uint64, cols []*column, rec *record) *sqlActionUpdateResponse {
	res := sqlActionUpdateResponse{
		pubsubid: pubsubid,
		cols:     cols,
	}
	// copy updated data
	l := len(cols)
	res.rec = &record{
		values: make([]string, l, l),
	}
	for idx, col := range cols {
		res.rec.setValue(idx, rec.getValue(col.ordinal))
	}
	return &res
}

// sqlUnsubscribeResponse
type sqlUnsubscribeResponse struct {
	requestIdResponse
	unsubscribed int
}

func (this *sqlUnsubscribeResponse) toNetworkReadyJSON() ([]byte, bool) {
	builder := networkReadyJSONBuilder()
	builder.beginObject()
	ok(builder)
	builder.valueSeparator()
	action(builder, "unsubscribe")
	builder.valueSeparator()
	builder.nameIntValue("subscriptions", this.unsubscribed)
	builder.endObject()
	return builder.getNetworkBytes(this.requestId), false
}
<commit_msg>response fix rows should return total number of rows, add fromrow, torow closes #31<commit_after>/* Copyright (C) 2013 CompleteDB LLC.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with PubSubSQL.  If not, see <http://www.gnu.org/licenses/>.
 */

package pubsubsql

import "strconv"

type responseStatusType int8

const (
	responseStatusOk  responseStatusType = iota // ok.
	responseStatusErr                           // error.
)

// response
type response interface {
	getResponseStatus() responseStatusType
	toNetworkReadyJSON() ([]byte, bool)
	setRequestId(requestId uint32)
}

type requestIdResponse struct {
	response
	requestId uint32
}

func (this *requestIdResponse) setRequestId(requestId uint32) {
	this.requestId = requestId
}

// json helper functions
func ok(builder *JSONBuilder) {
	builder.nameValue("status", "ok")
}

func id(builder *JSONBuilder, id string) {
	builder.nameValue("id", id)
}

func action(builder *JSONBuilder, action string) {
	builder.nameValue("action", action)
}

// errorResponse
type errorResponse struct {
	requestIdResponse
	msg string
}

func newErrorResponse(msg string) *errorResponse {
	return &errorResponse{
		msg: msg,
	}
}

func (this *errorResponse) getResponsStatus() responseStatusType {
	return responseStatusErr
}

func (this *errorResponse) toNetworkReadyJSON() ([]byte, bool) {
	builder := networkReadyJSONBuilder()
	builder.beginObject()
	builder.nameValue("status", "err")
	builder.valueSeparator()
	builder.nameValue("msg", this.msg)
	builder.endObject()
	return builder.getNetworkBytes(this.requestId), false
}

// okResponse
type okResponse struct {
	requestIdResponse
	action string
}

func newOkResponse(action string) *okResponse {
	return &okResponse{action: action}
}

func (this *okResponse) getResponsStatus() responseStatusType {
	return responseStatusOk
}

func (this *okResponse) toNetworkReadyJSON() ([]byte, bool) {
	builder := networkReadyJSONBuilder()
	builder.beginObject()
	ok(builder)
	builder.valueSeparator()
	action(builder, this.action)
	builder.endObject()
	return builder.getNetworkBytes(this.requestId), false
}

// cmdStatusResponse
type cmdStatusResponse struct {
	requestIdResponse
	connections int
}

func newCmdStatusResponse(connections int) *cmdStatusResponse {
	return &cmdStatusResponse{
		connections: connections,
	}
}

func (this *cmdStatusResponse) toNetworkReadyJSON() ([]byte, bool) {
	builder := networkReadyJSONBuilder()
	builder.beginObject()
	ok(builder)
	builder.valueSeparator()
	action(builder, "status")
	builder.valueSeparator()
	builder.nameIntValue("connections", this.connections)
	builder.endObject()
	return builder.getNetworkBytes(this.requestId), false
}

// sqlInsertResponse is a response for sql insert statement
type sqlInsertResponse struct {
	requestIdResponse
	id string
}

func newSqlInsertResponse(id string) *sqlInsertResponse {
	return &sqlInsertResponse{
		id: id,
	}
}

func (this *sqlInsertResponse) getResponsStatus() responseStatusType {
	return responseStatusOk
}

func (this *sqlInsertResponse) toNetworkReadyJSON() ([]byte, bool) {
	builder := networkReadyJSONBuilder()
	builder.beginObject()
	ok(builder)
	builder.valueSeparator()
	action(builder, "insert")
	builder.valueSeparator()
	id(builder, this.id)
	builder.endObject()
	return builder.getNetworkBytes(this.requestId), false
}

// sqlSelectResponse is a response for sql select statement
type sqlSelectResponse struct {
	requestIdResponse
	columns []*column
	records []*record
	//
	init bool
	rows int
	fromrow int
	torow int
}

func row(builder *JSONBuilder, columns []*column, rec *record) {
	builder.beginObject()
	// columns and values
	for colIndex, col := range columns {
		if colIndex != 0 {
			builder.valueSeparator()
		}
		builder.nameValue(col.name, rec.getValue(colIndex))
	}
	builder.endObject()
}

func (this *sqlSelectResponse) data(builder *JSONBuilder) bool {
	if !this.init {
		this.init = true
		this.rows = len(this.records)
	}
	more := len(this.records) > config.DATA_BATCH_SIZE
	records := this.records
	if more {
		records = this.records[0:config.DATA_BATCH_SIZE]
		this.records = this.records[config.DATA_BATCH_SIZE:]
		this.fromrow = this.torow + 1
		this.torow = this.fromrow + config.DATA_BATCH_SIZE - 1
	} else {
		if this.rows > 0 {
			this.fromrow = 1
			this.torow = this.rows
		}
	}
	// rows, fromrow, torow
	builder.nameIntValue("rows", this.rows)
	builder.valueSeparator()
	builder.nameIntValue("fromrow", this.fromrow)
	builder.valueSeparator()
	builder.nameIntValue("torow", this.torow)
	builder.valueSeparator()
	//
	builder.string("data")
	builder.nameSeparator()
	builder.beginArray()
	for recIndex, rec := range records {
		// another row
		if recIndex != 0 {
			builder.objectSeparator()
		}
		row(builder, this.columns, rec)
	}
	builder.endArray()
	return more
}

func (this *sqlSelectResponse) toNetworkReadyJSON() ([]byte, bool) {
	builder := networkReadyJSONBuilder()
	builder.beginObject()
	ok(builder)
	builder.valueSeparator()
	action(builder, "select")
	builder.valueSeparator()
	more := this.data(builder)
	builder.endObject()
	return builder.getNetworkBytes(this.requestId), more
}

func (this *sqlSelectResponse) copyRecordData(source *record) {
	l := len(this.columns)
	dest := &record{
		values: make([]string, l, l),
	}
	for idx, col := range this.columns {
		dest.setValue(idx, source.getValue(col.ordinal))
	}
	addRecordToSlice(&this.records, dest)
}

// sqlDeleteResponse
type sqlDeleteResponse struct {
	requestIdResponse
	deleted int
}

func (this *sqlDeleteResponse) toNetworkReadyJSON() ([]byte, bool) {
	builder := networkReadyJSONBuilder()
	builder.beginObject()
	ok(builder)
	builder.valueSeparator()
	action(builder, "delete")
	builder.valueSeparator()
	builder.nameIntValue("rows", this.deleted)
	builder.endObject()
	return builder.getNetworkBytes(this.requestId), false
}

// sqlUpdateResponse
type sqlUpdateResponse struct {
	requestIdResponse
	updated int
}

func (this *sqlUpdateResponse) toNetworkReadyJSON() ([]byte, bool) {
	builder := networkReadyJSONBuilder()
	builder.beginObject()
	ok(builder)
	builder.valueSeparator()
	action(builder, "update")
	builder.valueSeparator()
	builder.nameIntValue("rows", this.updated)
	builder.endObject()
	return builder.getNetworkBytes(this.requestId), false
}

// sqlSubscribeResponse
type sqlSubscribeResponse struct {
	requestIdResponse
	pubsubid uint64
}

func (this *sqlSubscribeResponse) toNetworkReadyJSON() ([]byte, bool) {
	builder := networkReadyJSONBuilder()
	builder.beginObject()
	ok(builder)
	builder.valueSeparator()
	action(builder, "subscribe")
	builder.valueSeparator()
	builder.nameValue("pubsubid", strconv.FormatUint(this.pubsubid, 10))
	builder.endObject()
	return builder.getNetworkBytes(this.requestId), false
}

func newSubscribeResponse(sub *subscription) response {
	return &sqlSubscribeResponse{
		pubsubid: sub.id,
	}
}

// sqlActionDataResponse
type sqlActionDataResponse struct {
	sqlSelectResponse
	pubsubid uint64
}

func (this *sqlActionDataResponse) toNetworkReadyJSONHelper(act string) ([]byte, bool) {
	builder := networkReadyJSONBuilder()
	builder.beginObject()
	ok(builder)
	builder.valueSeparator()
	action(builder, act)
	builder.valueSeparator()
	builder.nameValue("pubsubid", strconv.FormatUint(this.pubsubid, 10))
	builder.valueSeparator()
	more := this.data(builder)
	builder.endObject()
	return builder.getNetworkBytes(0), more
}

// sqlActionAddResponse
type sqlActionAddResponse struct {
	sqlActionDataResponse
}

func (this *sqlActionAddResponse) toNetworkReadyJSON() ([]byte, bool) {
	return this.toNetworkReadyJSONHelper("add")
}

// sqlActionInsertResponse
type sqlActionInsertResponse struct {
	sqlActionDataResponse
}

func (this *sqlActionInsertResponse) toNetworkReadyJSON() ([]byte, bool) {
	return this.toNetworkReadyJSONHelper("insert")
}

// sqlActonDeleteResponse
type sqlActionDeleteResponse struct {
	response
	id       string
	pubsubid uint64
}

func (this *sqlActionDeleteResponse) setRequestId(requestId uint32) {

}

func (this *sqlActionDeleteResponse) toNetworkReadyJSON() ([]byte, bool) {
	builder := networkReadyJSONBuilder()
	builder.beginObject()
	ok(builder)
	builder.valueSeparator()
	action(builder, "delete")
	builder.valueSeparator()
	builder.nameValue("pubsubid", strconv.FormatUint(this.pubsubid, 10))
	builder.valueSeparator()
	builder.nameValue("id", this.id)
	builder.endObject()
	return builder.getNetworkBytes(0), false
}

// sqlActionRemoveResponse
type sqlActionRemoveResponse struct {
	response
	id       string
	pubsubid uint64
}

func (this *sqlActionRemoveResponse) setRequestId(requestId uint32) {

}

func (this *sqlActionRemoveResponse) toNetworkReadyJSON() ([]byte, bool) {
	builder := networkReadyJSONBuilder()
	builder.beginObject()
	ok(builder)
	builder.valueSeparator()
	action(builder, "remove")
	builder.valueSeparator()
	builder.nameValue("pubsubid", strconv.FormatUint(this.pubsubid, 10))
	builder.valueSeparator()
	builder.nameValue("id", this.id)
	builder.endObject()
	return builder.getNetworkBytes(0), false
}

// sqlActionUpdateResponse
type sqlActionUpdateResponse struct {
	response
	pubsubid uint64
	cols     []*column
	rec      *record
}

func (this *sqlActionUpdateResponse) setRequestId(requestId uint32) {

}

func (this *sqlActionUpdateResponse) toNetworkReadyJSON() ([]byte, bool) {
	builder := networkReadyJSONBuilder()
	builder.beginObject()
	ok(builder)
	builder.valueSeparator()
	action(builder, "update")
	builder.valueSeparator()
	builder.nameValue("pubsubid", strconv.FormatUint(this.pubsubid, 10))
	builder.valueSeparator()

	builder.string("data")
	builder.nameSeparator()
	builder.beginArray()
	row(builder, this.cols, this.rec)
	builder.endArray()

	builder.endObject()
	return builder.getNetworkBytes(0), false
}

func newSqlActionUpdateResponse(pubsubid uint64, cols []*column, rec *record) *sqlActionUpdateResponse {
	res := sqlActionUpdateResponse{
		pubsubid: pubsubid,
		cols:     cols,
	}
	// copy updated data
	l := len(cols)
	res.rec = &record{
		values: make([]string, l, l),
	}
	for idx, col := range cols {
		res.rec.setValue(idx, rec.getValue(col.ordinal))
	}
	return &res
}

// sqlUnsubscribeResponse
type sqlUnsubscribeResponse struct {
	requestIdResponse
	unsubscribed int
}

func (this *sqlUnsubscribeResponse) toNetworkReadyJSON() ([]byte, bool) {
	builder := networkReadyJSONBuilder()
	builder.beginObject()
	ok(builder)
	builder.valueSeparator()
	action(builder, "unsubscribe")
	builder.valueSeparator()
	builder.nameIntValue("subscriptions", this.unsubscribed)
	builder.endObject()
	return builder.getNetworkBytes(this.requestId), false
}
<|endoftext|>


<commit_before>package service

import (
	"flag"
	"fmt"
	"strings"
)

// BootPrintln can be replaced with log.Println for printing debug information.
var BootPrintln = func(v ...interface{}) {}

// A Service wraps a Module (and its dependencies). It manages the lifecycle
// and allows the Module to be started and stopped. It maintains a
// topologically sorted list of the Modules, along with a map of the Modules'
// Configs and a map of registered commands.
type Service struct {
	Env Environment

	stopper  chan bool
	modules  []Module
	configs  map[string]*Config
	commands map[string]*Command
}

// New creates a new service with Module m as the entry point
func New(m Module) *Service {
	svc := New(m)
	svc.commands["start"] = &Command{
		Keyword:    "start",
		Run:        svc.cmdStart,
		ShortUsage: "Start the app",
		Usage:      "Start running the app",
	}
	return svc
}

// NewApp creates a new app with Module m as the entry point. Unlike
// New, `start` is not automatically registered.
func NewApp(m Module) *Service {
	return loadEnv(m, GetEnvironment())
}

// Run is a convenience method equivalent to "New(...).Run()"
func Run(m Module) {
	New(m).Run()
}

// Load the app with the given environment, and initializes
// all modules recursively starting with m.
func loadEnv(m Module, env Environment) *Service {
	svc := &Service{
		Env:      env,
		stopper:  make(chan bool),
		modules:  []Module{},
		configs:  map[string]*Config{},
		commands: map[string]*Command{},
	}
	svc.load(m)
	return svc
}

// Usage prints the usage for all registered commands.
func (s *Service) Usage() {
	for k, cmd := range s.commands {
		fmt.Printf("    %-16s %s\n", k, cmd.ShortUsage)
	}
}

// Run parses arguments from the command line and passes them to RunCommand.
func (s *Service) Run() {
	flag.Parse()
	args := flag.Args()
	if len(args) < 1 {
		s.Usage()
		BootPrintln()
		return
	}
	err := s.RunCommand(args[0], args[1:]...)
	if err != nil {
		BootPrintln(err)
	}
}

// RunCommand executes the given command, or returns an error if not found.
// module setup (and setupTest) will be called recursively before
// executing the command via cmd.Run. Meant for tests.
func (s *Service) RunCommand(command string, args ...string) error {
	cmd := s.commands[command]
	if cmd == nil {
		return fmt.Errorf("unknown command %q", command)
	}
	err := s.setup()
	if err != nil {
		return fmt.Errorf("error in setup: %v", err)
	}
	flagMap, err := parseArgs(cmd.Flags, args)
	if err != nil {
		return err
	}
	cmd.Run(&CommandContext{cmd, args, flagMap})
	return nil
}

// setup invokes `Setup()` on all loaded modules in topological order,
// dependencies first. If `service.Env.IsTest()`, it also runs
// each module's `SetupTest()` immediately after the module's `Setup()`
func (s *Service) setup() error {
	for _, m := range s.modules {
		n := getModuleName(m)
		c := s.configs[n]
		if c.Setup != nil {
			BootPrintln("[service] setup", n)
			err := c.Setup()
			if err != nil {
				return err
			}
		}

		if s.Env.IsTest() && c.SetupTest != nil {
			BootPrintln("[service] setup for test", n)
			c.SetupTest()
		}
	}
	return nil
}

func (s *Service) getConfig(m Module) *Config {
	n := getModuleName(m)
	return s.configs[n]
}

func (s *Service) registerCommand(cmd *Command) {
	kw := strings.Split(cmd.Keyword, " ")[0]
	_, ok := s.commands[kw]
	if ok {
		panic("keyword already registered: " + kw)
	}
	s.commands[kw] = cmd
}
<commit_msg>Bugfix<commit_after>package service

import (
	"flag"
	"fmt"
	"strings"
)

// BootPrintln can be replaced with log.Println for printing debug information.
var BootPrintln = func(v ...interface{}) {}

// A Service wraps a Module (and its dependencies). It manages the lifecycle
// and allows the Module to be started and stopped. It maintains a
// topologically sorted list of the Modules, along with a map of the Modules'
// Configs and a map of registered commands.
type Service struct {
	Env Environment

	stopper  chan bool
	modules  []Module
	configs  map[string]*Config
	commands map[string]*Command
}

// New creates a new service with Module m as the entry point
func New(m Module) *Service {
	svc := NewApp(m)
	svc.commands["start"] = &Command{
		Keyword:    "start",
		Run:        svc.cmdStart,
		ShortUsage: "Start the app",
		Usage:      "Start running the app",
	}
	return svc
}

// NewApp creates a new app with Module m as the entry point. Unlike
// New, `start` is not automatically registered.
func NewApp(m Module) *Service {
	return loadEnv(m, GetEnvironment())
}

// Run is a convenience method equivalent to "New(...).Run()"
func Run(m Module) {
	New(m).Run()
}

// Load the app with the given environment, and initializes
// all modules recursively starting with m.
func loadEnv(m Module, env Environment) *Service {
	svc := &Service{
		Env:      env,
		stopper:  make(chan bool),
		modules:  []Module{},
		configs:  map[string]*Config{},
		commands: map[string]*Command{},
	}
	svc.load(m)
	return svc
}

// Usage prints the usage for all registered commands.
func (s *Service) Usage() {
	for k, cmd := range s.commands {
		fmt.Printf("    %-16s %s\n", k, cmd.ShortUsage)
	}
}

// Run parses arguments from the command line and passes them to RunCommand.
func (s *Service) Run() {
	flag.Parse()
	args := flag.Args()
	if len(args) < 1 {
		s.Usage()
		BootPrintln()
		return
	}
	err := s.RunCommand(args[0], args[1:]...)
	if err != nil {
		BootPrintln(err)
	}
}

// RunCommand executes the given command, or returns an error if not found.
// module setup (and setupTest) will be called recursively before
// executing the command via cmd.Run. Meant for tests.
func (s *Service) RunCommand(command string, args ...string) error {
	cmd := s.commands[command]
	if cmd == nil {
		return fmt.Errorf("unknown command %q", command)
	}
	err := s.setup()
	if err != nil {
		return fmt.Errorf("error in setup: %v", err)
	}
	flagMap, err := parseArgs(cmd.Flags, args)
	if err != nil {
		return err
	}
	cmd.Run(&CommandContext{cmd, args, flagMap})
	return nil
}

// setup invokes `Setup()` on all loaded modules in topological order,
// dependencies first. If `service.Env.IsTest()`, it also runs
// each module's `SetupTest()` immediately after the module's `Setup()`
func (s *Service) setup() error {
	for _, m := range s.modules {
		n := getModuleName(m)
		c := s.configs[n]
		if c.Setup != nil {
			BootPrintln("[service] setup", n)
			err := c.Setup()
			if err != nil {
				return err
			}
		}

		if s.Env.IsTest() && c.SetupTest != nil {
			BootPrintln("[service] setup for test", n)
			c.SetupTest()
		}
	}
	return nil
}

func (s *Service) getConfig(m Module) *Config {
	n := getModuleName(m)
	return s.configs[n]
}

func (s *Service) registerCommand(cmd *Command) {
	kw := strings.Split(cmd.Keyword, " ")[0]
	_, ok := s.commands[kw]
	if ok {
		panic("keyword already registered: " + kw)
	}
	s.commands[kw] = cmd
}
<|endoftext|>


<commit_before>package service

import (
  "fmt"
  "log"
  "strconv"
  "github.com/docker/engine-api/client"
  "github.com/docker/engine-api/types"
  "github.com/docker/engine-api/types/filters"
  "golang.org/x/net/context"
)

type Service struct {
  Name string
  Port int
  DnsName string
}

func (s *Service) Url() string {
  return fmt.Sprintf("http://%s:%d", s.Name, s.Port)
}

func NewService(name string, port int, dnsName string) Service {
  return Service{Name: name, Port: port, DnsName: dnsName}
}

func LoadAll() []Service {
  defaultHeaders := map[string]string{"User-Agent": "engine-api-cli-1.0"}
  cli, err := client.NewClient("unix:///var/run/docker.sock", "v1.24", nil, defaultHeaders)
  if err != nil {
    panic(err)
  }

  filter := filters.NewArgs()

  filter.Add("label", "ingress=true")

  services, err := cli.ServiceList(context.Background(), types.ServiceListOptions{Filter: filter})
  if err != nil {
    panic(err)
  }

  numServices := len(services)

  serviceList := make([]Service, numServices)

  for i, s := range services {
    port, err := strconv.Atoi(s.Spec.Annotations.Labels["ingress.targetport"])
    if err != nil {
      log.Printf("Invalid port detected for service %s", s.Spec.Annotations.Name)
    } else {
      parsedService := NewService(s.Spec.Annotations.Name, port, s.Spec.Annotations.Labels["ingress.dnsname"])
      serviceList[i] = parsedService
    }

  }

  return serviceList
}
<commit_msg>Don't crash if service lookup fails<commit_after>package service

import (
  "fmt"
  "log"
  "strconv"
  "github.com/docker/engine-api/client"
  "github.com/docker/engine-api/types"
  "github.com/docker/engine-api/types/filters"
  "golang.org/x/net/context"
)

type Service struct {
  Name string
  Port int
  DnsName string
}

func (s *Service) Url() string {
  return fmt.Sprintf("http://%s:%d", s.Name, s.Port)
}

func NewService(name string, port int, dnsName string) Service {
  return Service{Name: name, Port: port, DnsName: dnsName}
}

func LoadAll() []Service {
  defaultHeaders := map[string]string{"User-Agent": "engine-api-cli-1.0"}
  cli, err := client.NewClient("unix:///var/run/docker.sock", "v1.24", nil, defaultHeaders)
	defer func() {
			if r := recover(); r != nil {
				log.Print("Failed to lookup services: ", r)
			}
	}()

  if err != nil {
		log.Print("Failed to lookup services: ", err)
    return make([]Service, 0)
  }

  filter := filters.NewArgs()

  filter.Add("label", "ingress=true")

  services, err := cli.ServiceList(context.Background(), types.ServiceListOptions{Filter: filter})
  if err != nil {
    panic(err)
  }

  numServices := len(services)

  serviceList := make([]Service, numServices)

  for i, s := range services {
    port, err := strconv.Atoi(s.Spec.Annotations.Labels["ingress.targetport"])
    if err != nil {
      log.Printf("Invalid port detected for service %s", s.Spec.Annotations.Name)
    } else {
      parsedService := NewService(s.Spec.Annotations.Name, port, s.Spec.Annotations.Labels["ingress.dnsname"])
      serviceList[i] = parsedService
    }

  }

  return serviceList
}
<|endoftext|>


<commit_before>package service

import (
	"errors"
	"fmt"
	"github.com/SudoQ/crisp/item"
	"github.com/SudoQ/crisp/external"
	"github.com/gorilla/mux"
	"io/ioutil"
	"log"
	"net/http"
	"net/url"
	"os"
	"time"
)

type Service struct {
	URL    string
	Port   string
	Period time.Duration
	Limit  uint
	Cache  *item.Item
	logger *log.Logger
	ext *external.Ext
}

func New(target, port string, limit uint) *Service {
	period, err := LimitToPeriod(limit)
	if err != nil {
		limit = 1
		period, _ = LimitToPeriod(limit)
	}
	srv := &Service{
		URL:    target,
		Port:   port,
		Period: period,
		Limit:  limit,
		Cache:  nil,
		logger: nil,
		ext: external.New(target, period),
	}
	srv.initLogger()
	return srv
}

func (this *Service) initLogger() {
	u, err := url.Parse(this.URL)
	label := u.Host
	if err != nil {
		label = "?"
	}
	this.logger = log.New(os.Stdin, fmt.Sprintf("crisp[%s]: ", label), log.Lshortfile)
}

func LimitToPeriod(limit uint) (time.Duration, error) {
	if limit == 0 {
		return 0, errors.New("Division with zero")
	}

	period := (60.0 / float64(limit)) * 60
	return (time.Duration(period) * time.Second), nil
}

func (this *Service) LoadCache(filename string) error {
	content, err := ioutil.ReadFile(filename)
	if err != nil {
		return err
	}
	newItem, err := item.NewFromJSON(content)
	if err != nil {
		return err
	}
	this.Cache = newItem
	return nil
}

func (this *Service) Info() string {
	return fmt.Sprintf("Crisp API caching service v0.1")
}

func (this *Service) Run() {
	err := this.LoadCache("cache.json")
	if err != nil {
		this.logger.Fatal(err)
	}
	dataCh := this.ext.DataChannel()
	defer this.ext.Close()
	go this.ext.Collect()
	go func() {
		for payload := range dataCh {
			newItem := item.New(time.Now(), payload)
			this.Cache = newItem
			cacheFilename := "cache.json"
			err = this.Cache.WriteFile(cacheFilename)
			if err != nil {
				this.logger.Fatal(err)
			}
			this.logger.Printf("Saved cache to %s\n", cacheFilename)
		}
	}()

	r := mux.NewRouter()
	r.HandleFunc("/", this.HomeHandler)
	r.HandleFunc("/info", this.InfoHandler)
	r.HandleFunc("/cache.json", this.CacheHandler)
	port := fmt.Sprintf(":%s", this.Port)
	http.ListenAndServe(port, r)
}

func (this *Service) HomeHandler(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "application/json")
	w.WriteHeader(200)
	w.Write(this.Cache.Payload)
}

func (this *Service) InfoHandler(w http.ResponseWriter, r *http.Request) {
	w.WriteHeader(200)
	w.Write([]byte(this.Info()))
}

func (this *Service) CacheHandler(w http.ResponseWriter, r *http.Request) {
	response, err := this.Cache.JSON()
	if err != nil {
		this.logger.Println(err)
		w.WriteHeader(404)
		return
	}
	w.Header().Set("Content-Type", "application/json")
	w.WriteHeader(200)
	w.Write(response)
}
<commit_msg>Using storage struct instead of one item<commit_after>package service

import (
	"errors"
	"fmt"
	"github.com/SudoQ/crisp/item"
	"github.com/SudoQ/crisp/external"
	"github.com/SudoQ/crisp/storage"
	"github.com/gorilla/mux"
	"io/ioutil"
	"log"
	"net/http"
	"net/url"
	"os"
	"time"
)

type Service struct {
	URL    string
	Port   string
	Period time.Duration
	Limit  uint
	Cache  *storage.Store
	logger *log.Logger
	ext *external.Ext
}

func New(target, port string, limit uint) *Service {
	period, err := LimitToPeriod(limit)
	if err != nil {
		limit = 1
		period, _ = LimitToPeriod(limit)
	}
	srv := &Service{
		URL:    target,
		Port:   port,
		Period: period,
		Limit:  limit,
		Cache:  storage.New(),
		logger: nil,
		ext: external.New(target, period),
	}
	srv.initLogger()
	return srv
}

func (this *Service) initLogger() {
	u, err := url.Parse(this.URL)
	label := u.Host
	if err != nil {
		label = "?"
	}
	this.logger = log.New(os.Stdin, fmt.Sprintf("crisp[%s]: ", label), log.Lshortfile)
}

func LimitToPeriod(limit uint) (time.Duration, error) {
	if limit == 0 {
		return 0, errors.New("Division with zero")
	}

	period := (60.0 / float64(limit)) * 60
	return (time.Duration(period) * time.Second), nil
}

func (this *Service) LoadCache(filename string) error {
	content, err := ioutil.ReadFile(filename)
	if err != nil {
		return err
	}
	newItem, err := item.NewFromJSON(content)
	if err != nil {
		return err
	}
	this.Cache.Add(newItem)
	return nil
}

func (this *Service) Info() string {
	return fmt.Sprintf("Crisp API caching service v0.1")
}

func (this *Service) Run() {
	err := this.LoadCache("cache.json")
	if err != nil {
		this.logger.Fatal(err)
	}
	dataCh := this.ext.DataChannel()
	defer this.ext.Close()
	go this.ext.Collect()
	go func() {
		for payload := range dataCh {
			newItem := item.New(time.Now(), payload)
			this.Cache.Add(newItem)
			cacheFilename := "cache.json"
			latestItem, _ := this.Cache.Get()
			err = latestItem.WriteFile(cacheFilename)
			if err != nil {
				this.logger.Fatal(err)
			}
			this.logger.Printf("Saved cache to %s\n", cacheFilename)
		}
	}()

	r := mux.NewRouter()
	r.HandleFunc("/", this.HomeHandler)
	r.HandleFunc("/info", this.InfoHandler)
	r.HandleFunc("/cache.json", this.CacheHandler)
	port := fmt.Sprintf(":%s", this.Port)
	http.ListenAndServe(port, r)
}

func (this *Service) HomeHandler(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "application/json")
	w.WriteHeader(200)
	latestItem, _ := this.Cache.Get()
	w.Write(latestItem.Payload)
}

func (this *Service) InfoHandler(w http.ResponseWriter, r *http.Request) {
	w.WriteHeader(200)
	w.Write([]byte(this.Info()))
}

func (this *Service) CacheHandler(w http.ResponseWriter, r *http.Request) {
	latestItem, _ := this.Cache.Get()
	response, err := latestItem.JSON()
	if err != nil {
		this.logger.Println(err)
		w.WriteHeader(404)
		return
	}
	w.Header().Set("Content-Type", "application/json")
	w.WriteHeader(200)
	w.Write(response)
}
<|endoftext|>


<commit_before>// Copyright (C) 2017 Jennal(jennalcn@gmail.com). All rights reserved.
//
// Licensed under the MIT License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at
//
// http://opensource.org/licenses/MIT
//
// 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 service

import (
	"fmt"
	"reflect"

	"github.com/jennal/goplay/aop"
	"github.com/jennal/goplay/defaults"
	"github.com/jennal/goplay/encode"
	"github.com/jennal/goplay/filter"
	"github.com/jennal/goplay/filter/heartbeat"
	"github.com/jennal/goplay/handler"
	"github.com/jennal/goplay/helpers"
	"github.com/jennal/goplay/log"
	"github.com/jennal/goplay/pkg"
	"github.com/jennal/goplay/router"
	"github.com/jennal/goplay/session"
	"github.com/jennal/goplay/transfer"
)

type Service struct {
	transfer.IServer
	router *router.Router

	Name     string
	Encoding pkg.EncodingType

	handlers []handler.IHandler
	filters  []filter.IFilter
}

func NewService(name string, serv transfer.IServer) *Service {
	instance := &Service{
		Name:     name,
		Encoding: defaults.Encoding,
		IServer:  serv,
		router:   router.NewRouter(name),
	}

	serv.RegistDelegate(instance)
	instance.RegistFilter(heartbeat.NewHeartBeatManager())

	return instance
}

func (self *Service) SetEncoding(e pkg.EncodingType) error {
	if encoder := encode.GetEncodeDecoder(e); encoder != nil {
		self.Encoding = e
		return nil
	}

	return log.NewErrorf("can't find encoder with: %v", e)
}

func (self *Service) RegistHanlder(obj handler.IHandler) {
	self.router.Add(obj)
	self.handlers = append(self.handlers, obj)
}

func (self *Service) RegistFilter(obj filter.IFilter) {
	self.filters = append(self.filters, obj)
}

func (self *Service) OnStarted() {
	fmt.Printf("OnStarted %p\n", self)
	for _, handler := range self.handlers {
		handler.OnStarted()
	}
}
func (self *Service) OnError(err error) {
	fmt.Println("OnError", err)
}
func (self *Service) OnStopped() {
	fmt.Println("OnStopped")
	for _, handler := range self.handlers {
		handler.OnStopped()
	}
}
func (self *Service) OnNewClient(client transfer.IClient) {
	fmt.Println("OnNewClient", client)
	sess := session.NewSession(client)
	sess.SetEncoding(self.Encoding)

	for _, filter := range self.filters {
		if !filter.OnNewClient(sess) {
			return
		}
	}

	for _, handler := range self.handlers {
		handler.OnNewClient(sess)
	}

	go func() {
		for {
		NextLoop:
			header, bodyBuf, err := client.Recv()
			if header.Type != pkg.PKG_HEARTBEAT && header.Type != pkg.PKG_HEARTBEAT_RESPONSE {
				log.Logf("Recv:\n\theader => %#v\n\tbody => %#v | %v\n\terr => %v\n", header, bodyBuf, string(bodyBuf), err)
			}

			if err != nil {
				log.Errorf("Recv:\n\terr => %v\n\theader => %#v\n\tbody => %#v | %v", err, header, bodyBuf, string(bodyBuf))
				sess.Disconnect()
				break
			}

			//filters
			for _, filter := range self.filters {
				if !filter.OnRecv(sess, header, bodyBuf) {
					goto NextLoop
				}
			}

			//map to handler
			switch header.Type {
			case pkg.PKG_NOTIFY:
				_, err := self.callRouteFunc(sess, header, bodyBuf)
				if err != nil {
					log.Errorf("CallRouteFunc:\n\terr => %v\n\theader => %#v\n\tbody => %#v | %v", err, header, bodyBuf, string(bodyBuf))
					sess.Disconnect()
					break
				}
			case pkg.PKG_REQUEST:
				results, err := self.callRouteFunc(sess, header, bodyBuf)
				if err != nil {
					log.Errorf("CallRouteFunc:\n\terr => %v\n\theader => %#v\n\tbody => %#v | %v", err, header, bodyBuf, string(bodyBuf))
					sess.Disconnect()
					break
				}
				// fmt.Printf(" => Loop result: %#v\n", results)
				err = self.response(sess, header, results)
				if err != nil {
					log.Errorf("Response:\n\terr => %v\n\theader => %#v\n\tresults => %#v", err, header, results)
					sess.Disconnect()
					break
				}
			case pkg.PKG_HEARTBEAT: /* Can not come to here */
				fallthrough
			case pkg.PKG_HEARTBEAT_RESPONSE: /* Can not come to here */
				fallthrough
			default:
				log.Errorf("Can't reach here!!\n\terr => %v\n\theader => %#v\n\tbody => %#v", err, header, bodyBuf)
			}
		}
	}()
}

func (self *Service) callRouteFunc(sess *session.Session, header *pkg.Header, bodyBuf []byte) ([]interface{}, error) {
	/*
	 * 1. find route func
	 * 2. unmarshal data
	 * 3. call route func
	 */
	method := self.router.Get(header.Route)
	if method == nil {
		return nil, log.NewErrorf("Can't find method with route: %s", header.Route)
	}
	val := method.NewArg(2)
	// fmt.Printf("Service.callRouteFunc: %#v => %v\n", val, reflect.TypeOf(val))
	decoder := encode.GetEncodeDecoder(header.Encoding)
	err := decoder.Unmarshal(bodyBuf, val)
	if err != nil {
		return nil, log.NewErrorf("Service.callRouteFunc decoder.Unmarshal failed: %v", err)
	}
	// fmt.Printf("Service.callRouteFunc: %#v => %v\n", val, reflect.TypeOf(val))

	var result []interface{}
	aop.Recover(func() {
		result = method.Call(sess, helpers.GetValueFromPtr(val))
	}, func(e interface{}) {
		err = e.(error)
	})

	return result, err
}

func (self *Service) response(sess *session.Session, header *pkg.Header, results []interface{}) error {
	respHeader := *header
	respHeader.Type = pkg.PKG_RESPONSE

	if results == nil || len(results) <= 0 {
		return sess.Send(&respHeader, []byte{})
	}

	result := results[0]
	/* check error != nil */
	if len(results) == 2 && !reflect.ValueOf(results[1]).IsNil() {
		header.Status = pkg.STAT_ERR
		result = results[1]
	}

	// fmt.Println("result:", result)

	encoder := encode.GetEncodeDecoder(header.Encoding)
	body, err := encoder.Marshal(result)
	if err != nil {
		return err
	}

	return sess.Send(&respHeader, body)
}
<commit_msg>add blank lines<commit_after>// Copyright (C) 2017 Jennal(jennalcn@gmail.com). All rights reserved.
//
// Licensed under the MIT License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at
//
// http://opensource.org/licenses/MIT
//
// 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 service

import (
	"fmt"
	"reflect"

	"github.com/jennal/goplay/aop"
	"github.com/jennal/goplay/defaults"
	"github.com/jennal/goplay/encode"
	"github.com/jennal/goplay/filter"
	"github.com/jennal/goplay/filter/heartbeat"
	"github.com/jennal/goplay/handler"
	"github.com/jennal/goplay/helpers"
	"github.com/jennal/goplay/log"
	"github.com/jennal/goplay/pkg"
	"github.com/jennal/goplay/router"
	"github.com/jennal/goplay/session"
	"github.com/jennal/goplay/transfer"
)

type Service struct {
	transfer.IServer
	router *router.Router

	Name     string
	Encoding pkg.EncodingType

	handlers []handler.IHandler
	filters  []filter.IFilter
}

func NewService(name string, serv transfer.IServer) *Service {
	instance := &Service{
		Name:     name,
		Encoding: defaults.Encoding,
		IServer:  serv,
		router:   router.NewRouter(name),
	}

	serv.RegistDelegate(instance)
	instance.RegistFilter(heartbeat.NewHeartBeatManager())

	return instance
}

func (self *Service) SetEncoding(e pkg.EncodingType) error {
	if encoder := encode.GetEncodeDecoder(e); encoder != nil {
		self.Encoding = e
		return nil
	}

	return log.NewErrorf("can't find encoder with: %v", e)
}

func (self *Service) RegistHanlder(obj handler.IHandler) {
	self.router.Add(obj)
	self.handlers = append(self.handlers, obj)
}

func (self *Service) RegistFilter(obj filter.IFilter) {
	self.filters = append(self.filters, obj)
}

func (self *Service) OnStarted() {
	fmt.Printf("OnStarted %p\n", self)
	for _, handler := range self.handlers {
		handler.OnStarted()
	}
}

func (self *Service) OnError(err error) {
	fmt.Println("OnError", err)
}

func (self *Service) OnStopped() {
	fmt.Println("OnStopped")
	for _, handler := range self.handlers {
		handler.OnStopped()
	}
}

func (self *Service) OnNewClient(client transfer.IClient) {
	fmt.Println("OnNewClient", client)
	sess := session.NewSession(client)
	sess.SetEncoding(self.Encoding)

	for _, filter := range self.filters {
		if !filter.OnNewClient(sess) {
			return
		}
	}

	for _, handler := range self.handlers {
		handler.OnNewClient(sess)
	}

	go func() {
		for {
		NextLoop:
			header, bodyBuf, err := client.Recv()
			if header.Type != pkg.PKG_HEARTBEAT && header.Type != pkg.PKG_HEARTBEAT_RESPONSE {
				log.Logf("Recv:\n\theader => %#v\n\tbody => %#v | %v\n\terr => %v\n", header, bodyBuf, string(bodyBuf), err)
			}

			if err != nil {
				log.Errorf("Recv:\n\terr => %v\n\theader => %#v\n\tbody => %#v | %v", err, header, bodyBuf, string(bodyBuf))
				sess.Disconnect()
				break
			}

			//filters
			for _, filter := range self.filters {
				if !filter.OnRecv(sess, header, bodyBuf) {
					goto NextLoop
				}
			}

			//map to handler
			switch header.Type {
			case pkg.PKG_NOTIFY:
				_, err := self.callRouteFunc(sess, header, bodyBuf)
				if err != nil {
					log.Errorf("CallRouteFunc:\n\terr => %v\n\theader => %#v\n\tbody => %#v | %v", err, header, bodyBuf, string(bodyBuf))
					sess.Disconnect()
					break
				}
			case pkg.PKG_REQUEST:
				results, err := self.callRouteFunc(sess, header, bodyBuf)
				if err != nil {
					log.Errorf("CallRouteFunc:\n\terr => %v\n\theader => %#v\n\tbody => %#v | %v", err, header, bodyBuf, string(bodyBuf))
					sess.Disconnect()
					break
				}
				// fmt.Printf(" => Loop result: %#v\n", results)
				err = self.response(sess, header, results)
				if err != nil {
					log.Errorf("Response:\n\terr => %v\n\theader => %#v\n\tresults => %#v", err, header, results)
					sess.Disconnect()
					break
				}
			case pkg.PKG_HEARTBEAT: /* Can not come to here */
				fallthrough
			case pkg.PKG_HEARTBEAT_RESPONSE: /* Can not come to here */
				fallthrough
			default:
				log.Errorf("Can't reach here!!\n\terr => %v\n\theader => %#v\n\tbody => %#v", err, header, bodyBuf)
			}
		}
	}()
}

func (self *Service) callRouteFunc(sess *session.Session, header *pkg.Header, bodyBuf []byte) ([]interface{}, error) {
	/*
	 * 1. find route func
	 * 2. unmarshal data
	 * 3. call route func
	 */
	method := self.router.Get(header.Route)
	if method == nil {
		return nil, log.NewErrorf("Can't find method with route: %s", header.Route)
	}
	val := method.NewArg(2)
	// fmt.Printf("Service.callRouteFunc: %#v => %v\n", val, reflect.TypeOf(val))
	decoder := encode.GetEncodeDecoder(header.Encoding)
	err := decoder.Unmarshal(bodyBuf, val)
	if err != nil {
		return nil, log.NewErrorf("Service.callRouteFunc decoder.Unmarshal failed: %v", err)
	}
	// fmt.Printf("Service.callRouteFunc: %#v => %v\n", val, reflect.TypeOf(val))

	var result []interface{}
	aop.Recover(func() {
		result = method.Call(sess, helpers.GetValueFromPtr(val))
	}, func(e interface{}) {
		err = e.(error)
	})

	return result, err
}

func (self *Service) response(sess *session.Session, header *pkg.Header, results []interface{}) error {
	respHeader := *header
	respHeader.Type = pkg.PKG_RESPONSE

	if results == nil || len(results) <= 0 {
		return sess.Send(&respHeader, []byte{})
	}

	result := results[0]
	/* check error != nil */
	if len(results) == 2 && !reflect.ValueOf(results[1]).IsNil() {
		header.Status = pkg.STAT_ERR
		result = results[1]
	}

	// fmt.Println("result:", result)

	encoder := encode.GetEncodeDecoder(header.Encoding)
	body, err := encoder.Marshal(result)
	if err != nil {
		return err
	}

	return sess.Send(&respHeader, body)
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"github.com/HewlettPackard/oneview-golang/ov"
	"github.com/HewlettPackard/oneview-golang/utils"
	"os"
)

func newTrue() *bool {
	b := true
	return &b
}
func newFalse() *bool {
	b := false
	return &b
}

func main() {
	var (
		clientOV   *ov.OVClient
		id         = "7a8b37a6-bde0-4d06-8d20-6e574c50f39f"
		macAddress = ""
		//macAddress      = "94:57:A5:67:2C:BE"
		//internalVlan    = "504"
		internalVlan    = ""
		interconnectURI = "/rest/interconnects/b6b7325f-666f-474f-a8f7-2c32b3c9faab"
		externalVlan    = ""
		tcId            = "1"
	)
	ovc := clientOV.NewOVClient(
		os.Getenv("ONEVIEW_OV_USER"),
		os.Getenv("ONEVIEW_OV_PASSWORD"),
		os.Getenv("ONEVIEW_OV_DOMAIN"),
		os.Getenv("ONEVIEW_OV_ENDPOINT"),
		false,
		1000,
		"*")

	fmt.Println("....  Logical Interconnects Collection .....")
	logicalInterconnectList, _ := ovc.GetLogicalInterconnects("", "0", "10")
	fmt.Println(logicalInterconnectList)

	fmt.Println("....  Logical Interconnect by Id.....")
	lig, _ := ovc.GetLogicalInterconnectById(id)
	fmt.Println(lig)

	fmt.Println("....  Logical Interconnect PortMonitor.....")
	portMonitor, _ := ovc.GetLogicalInterconnectPortMonitor(id)
	fmt.Println(portMonitor)

	fmt.Println("....  Logical Interconnect EthernetSettings.....")
	ethernetSettings, _ := ovc.GetLogicalInterconnectEthernetSettings(id)
	fmt.Println(ethernetSettings)

	fmt.Println("....  Logical Interconnect Firmware.....")
	firmware, _ := ovc.GetLogicalInterconnectFirmware(id)
	fmt.Println(firmware)

	fmt.Println("....  Logical Interconnect SNMPConfiguration.....")
	snmpconfig, _ := ovc.GetLogicalInterconnectSNMPConfiguration(id)
	fmt.Println(snmpconfig)

	fmt.Println("....  Logical Interconnect Forwarding Information.....")
	var filter []string
	fi, _ := ovc.GetLogicalInterconnectForwardingInformation(filter, id)
	fmt.Println(fi)

	fmt.Println("....  Logical Interconnect Forwarding Information By Mac Address.....")
	fi_mac, _ := ovc.GetLogicalInterconnectForwardingInformationByMacAddress(macAddress, id)
	fmt.Println(fi_mac)

	fmt.Println("....  Logical Interconnect Forwarding Information By Internal Vlan.....")
	fi_intern_vlan, _ := ovc.GetLogicalInterconnectForwardingInformationByInternalVlan(internalVlan, id)
	fmt.Println(fi_intern_vlan)

	fmt.Println("....  Logical Interconnect Forwarding Information By Interconnect URI and ExternalVlan.....")
	fi_interconnect_external, _ := ovc.GetLogicalInterconnectForwardingInformationByInterconnectAndExternalVlan(interconnectURI, externalVlan, id)
	fmt.Println(fi_interconnect_external)

	fmt.Println("....  Logical Interconnect Internal VLAN IDs for the provisioned networks.....")
	fi_internal_vlan, _ := ovc.GetLogicalInternalVlans(id)
	fmt.Println(fi_internal_vlan)

	fmt.Println("....  Logical Interconnect QOS Configuration.....")
	fi_qos_config, _ := ovc.GetLogicalQosAggregatedConfiguration(id, "", "expand")
	fmt.Println(fi_qos_config)

	fmt.Println("....  Logical Interconnect Unassigned Ports for Port Monitor.....")
	port_monitor_ports := ovc.GetUnassignedPortsForPortMonitor(id)
	fmt.Println(port_monitor_ports)

	fmt.Println("....  Logical Interconnect Unassigned Uplink Ports for Port Monitor.....")
	uplink_port_monitor_ports, _ := ovc.GetUnassignedUplinkPortsForPortMonitor(id)
	fmt.Println(uplink_port_monitor_ports)

	fmt.Println("....  Logical Interconnect Telemetry Configuration.....")
	telemetry_config, _ := ovc.GetTelemetryConfigurations(id, "1")
	fmt.Println(telemetry_config)

	fmt.Println("....  Updating Logical Interconnect Consistent State.....")
	var liUris []utils.Nstring
	liUris = append(liUris, utils.NewNstring("/rest/logical-interconnects/d4468f89-4442-4324-9c01-624c7382db2d"))
	liCompliance := ov.LogicalInterconnectCompliance{Type: "li-compliance",
		LogicalInterconnectUris: liUris,
		Description:             ""}
	err_compliance := ovc.UpdateLogicalInterconnectConsistentState(liCompliance)
	if err_compliance != nil {
		fmt.Println("Could not update ConsistentState of Logical Interconnect", err_compliance)
	}

	fmt.Println(".... Updating Logical Interconnect Consistent State by ID ....")
	err_update_compliance := ovc.UpdateLogicalInterconnectConsistentStateById(id)
	if err_update_compliance != nil {
		fmt.Println("Could not update ConsistentState of Logical Interconnect", err_update_compliance)
	}

	fmt.Println("....  Updating Logical Interconnect EthernetSetting .....")
	liEthernetSettings := ov.EthernetSettings{Type: "EthernetInterconnectSettingsV4",
		InterconnectType: "Ethernet",
		URI:              utils.NewNstring("/rest/logical-interconnects/d4468f89-4442-4324-9c01-624c7382db2d/ethernetSettings"),
		ID:               "d4468f89-4442-4324-9c01-624c7382db2d"}
	err_ethernet := ovc.UpdateLogicalInterconnectEthernetSettings(liEthernetSettings, id)
	if err_ethernet != nil {
		fmt.Println("Could not update Ethernet Settings of Logical Interconnect", err_ethernet)
	}

	fmt.Println("....  Updating Logical Interconnect EthernetSetting Force.....")
	err_ethernet_force := ovc.UpdateLogicalInterconnectEthernetSettingsForce(liEthernetSettings, id, true)
	if err_ethernet_force != nil {
		fmt.Println("Could not update Ethernet Settings of Logical Interconnect", err_ethernet_force)
	}

	fmt.Println("....  Updating Logical Interconnect Firmware.....")
	liFirmware := ov.Firmware{Command: "Update",
		EthernetActivationDelay: 5,
		EthernetActivationType:  "Parallel",
		FcActivationDelay:       5,
		FcActivationType:        "Parallel",
		Force:                   false,
		SppUri:                  utils.NewNstring("/rest/firmware-drivers/SPP_2018_06_20180709_for_HPE_Synergy_Z7550-96524")}
	err_firmware := ovc.UpdateLogicalInterconnectFirmware(liFirmware, id)
	if err_firmware != nil {
		fmt.Println("Could not update Firmware of Logical Interconnect", err_firmware)
	}

	fmt.Println("....  Updating Logical Interconnect Firmware Force.....")
	err_firmware_force := ovc.UpdateLogicalInterconnectFirmwareForce(liFirmware, id, true)
	if err_firmware_force != nil {
		fmt.Println("Could not update Firmware of Logical Interconnect", err_firmware_force)
	}

	fmt.Println("....  Updating Logical Interconnect InternalNetworks.....")
	var internalNetworks []utils.Nstring
	internalNetworks = append(internalNetworks, utils.NewNstring("/rest/ethernet-networks/a71b9c9e-b044-48ee-8e4e-26ced1a9a9ef"))
	err_networks := ovc.UpdateLogicalInterconnectInternalNetworks(internalNetworks, id)
	if err_networks != nil {
		fmt.Println("Could not update Internal Networks of Logical Interconnect", err_networks)
	}
	fmt.Println("....  Updating Logical Interconnect InternalNetworks Force.....")
	err_networks_force := ovc.UpdateLogicalInterconnectInternalNetworksForce(internalNetworks, id, true)
	if err_networks_force != nil {
		fmt.Println("Could not update Internal Networks of Logical Interconnect", err_networks_force)
	}

	fmt.Println("....  Updating Logical Interconnect QOS Configuration.....")
	liActiveQosConfig := ov.ActiveQosConfig{Type: "QosConfiguration", Category: "qos-aggregated-configuration", ConfigType: "Passthrough"}
	liQosConfig := ov.QosConfiguration{Type: "qos-aggregated-configuration", Category: "qos-aggregated-configuration", ActiveQosConfig: liActiveQosConfig}

	err_qos := ovc.UpdateLogicalInterconnectQosConfigurations(liQosConfig, id)
	if err_qos != nil {
		fmt.Println("Could not update QOS Configuration of Logical Interconnect", err_qos)
	}

	fmt.Println("....  Updating Logical Interconnect SNMP Configuration.....")
	liSNMPConfig := ov.SnmpConfiguration{Type: "snmp-configuration", Category: "snmp-configuration", V3Enabled: newTrue()}

	err_snmp := ovc.UpdateLogicalInterconnectSNMPConfigurations(liSNMPConfig, id)
	if err_snmp != nil {
		fmt.Println("Could not update SNMP Configuration of Logical Interconnect", err_snmp)
	}

	fmt.Println("....  Updating Logical Interconnect Configuration.....")
	err_conf := ovc.UpdateLogicalInterconnectConfigurations(id)
	if err_conf != nil {
		fmt.Println("Could not update Configuration of Logical Interconnect", err_conf)
	}

	fmt.Println("....  Updating Logical Interconnect Port Monitor Configuration.....")
	liPMConfig := ov.PortMonitor{Type: "port-monitor", Category: "port-monitor", ETAG: "8a302a85-ec4d-4214-a3e0-10ef71d28769", Name: "name2095641007-1533682087640"}

	err_pm := ovc.UpdateLogicalInterconnectPortMonitor(liPMConfig, id)
	if err_pm != nil {
		fmt.Println("Could not update PortMonitor Configuration of Logical Interconnect", err_pm)
	}

	fmt.Println("....  Updating Logical Interconnect Telemetry  Configuration.....")
	liTMConfig := ov.TelemetryConfiguration{Type: "telemetry-configuration", EnableTelemetry: newTrue(), SampleInterval: 300, SampleCount: 12, Name: "name771327580-1533682118441"}

	err_tm := ovc.UpdateLogicalInterconnectTelemetryConfigurations(liTMConfig, id, tcId)
	if err_tm != nil {
		fmt.Println("Could not update PortMonitor Configuration of Logical Interconnect", err_tm)
	}

}
<commit_msg>Removing commented code from example<commit_after>package main

import (
	"fmt"
	"github.com/HewlettPackard/oneview-golang/ov"
	"github.com/HewlettPackard/oneview-golang/utils"
	"os"
)

func newTrue() *bool {
	b := true
	return &b
}
func newFalse() *bool {
	b := false
	return &b
}

func main() {
	var (
		clientOV   *ov.OVClient
		id         = "7a8b37a6-bde0-4d06-8d20-6e574c50f39f"
		macAddress      = "94:57:A5:67:2C:BE"
		internalVlan    = "504"
		interconnectURI = "/rest/interconnects/b6b7325f-666f-474f-a8f7-2c32b3c9faab"
		externalVlan    = "504"
		tcId            = "1"
	)
	ovc := clientOV.NewOVClient(
		os.Getenv("ONEVIEW_OV_USER"),
		os.Getenv("ONEVIEW_OV_PASSWORD"),
		os.Getenv("ONEVIEW_OV_DOMAIN"),
		os.Getenv("ONEVIEW_OV_ENDPOINT"),
		false,
		1000,
		"*")

	fmt.Println("....  Logical Interconnects Collection .....")
	logicalInterconnectList, _ := ovc.GetLogicalInterconnects("", "0", "10")
	fmt.Println(logicalInterconnectList)

	fmt.Println("....  Logical Interconnect by Id.....")
	lig, _ := ovc.GetLogicalInterconnectById(id)
	fmt.Println(lig)

	fmt.Println("....  Logical Interconnect PortMonitor.....")
	portMonitor, _ := ovc.GetLogicalInterconnectPortMonitor(id)
	fmt.Println(portMonitor)

	fmt.Println("....  Logical Interconnect EthernetSettings.....")
	ethernetSettings, _ := ovc.GetLogicalInterconnectEthernetSettings(id)
	fmt.Println(ethernetSettings)

	fmt.Println("....  Logical Interconnect Firmware.....")
	firmware, _ := ovc.GetLogicalInterconnectFirmware(id)
	fmt.Println(firmware)

	fmt.Println("....  Logical Interconnect SNMPConfiguration.....")
	snmpconfig, _ := ovc.GetLogicalInterconnectSNMPConfiguration(id)
	fmt.Println(snmpconfig)

	fmt.Println("....  Logical Interconnect Forwarding Information.....")
	var filter []string
	fi, _ := ovc.GetLogicalInterconnectForwardingInformation(filter, id)
	fmt.Println(fi)

	fmt.Println("....  Logical Interconnect Forwarding Information By Mac Address.....")
	fi_mac, _ := ovc.GetLogicalInterconnectForwardingInformationByMacAddress(macAddress, id)
	fmt.Println(fi_mac)

	fmt.Println("....  Logical Interconnect Forwarding Information By Internal Vlan.....")
	fi_intern_vlan, _ := ovc.GetLogicalInterconnectForwardingInformationByInternalVlan(internalVlan, id)
	fmt.Println(fi_intern_vlan)

	fmt.Println("....  Logical Interconnect Forwarding Information By Interconnect URI and ExternalVlan.....")
	fi_interconnect_external, _ := ovc.GetLogicalInterconnectForwardingInformationByInterconnectAndExternalVlan(interconnectURI, externalVlan, id)
	fmt.Println(fi_interconnect_external)

	fmt.Println("....  Logical Interconnect Internal VLAN IDs for the provisioned networks.....")
	fi_internal_vlan, _ := ovc.GetLogicalInternalVlans(id)
	fmt.Println(fi_internal_vlan)

	fmt.Println("....  Logical Interconnect QOS Configuration.....")
	fi_qos_config, _ := ovc.GetLogicalQosAggregatedConfiguration(id, "", "expand")
	fmt.Println(fi_qos_config)

	fmt.Println("....  Logical Interconnect Unassigned Ports for Port Monitor.....")
	port_monitor_ports := ovc.GetUnassignedPortsForPortMonitor(id)
	fmt.Println(port_monitor_ports)

	fmt.Println("....  Logical Interconnect Unassigned Uplink Ports for Port Monitor.....")
	uplink_port_monitor_ports, _ := ovc.GetUnassignedUplinkPortsForPortMonitor(id)
	fmt.Println(uplink_port_monitor_ports)

	fmt.Println("....  Logical Interconnect Telemetry Configuration.....")
	telemetry_config, _ := ovc.GetTelemetryConfigurations(id, "1")
	fmt.Println(telemetry_config)

	fmt.Println("....  Updating Logical Interconnect Consistent State.....")
	var liUris []utils.Nstring
	liUris = append(liUris, utils.NewNstring("/rest/logical-interconnects/d4468f89-4442-4324-9c01-624c7382db2d"))
	liCompliance := ov.LogicalInterconnectCompliance{Type: "li-compliance",
		LogicalInterconnectUris: liUris,
		Description:             ""}
	err_compliance := ovc.UpdateLogicalInterconnectConsistentState(liCompliance)
	if err_compliance != nil {
		fmt.Println("Could not update ConsistentState of Logical Interconnect", err_compliance)
	}

	fmt.Println(".... Updating Logical Interconnect Consistent State by ID ....")
	err_update_compliance := ovc.UpdateLogicalInterconnectConsistentStateById(id)
	if err_update_compliance != nil {
		fmt.Println("Could not update ConsistentState of Logical Interconnect", err_update_compliance)
	}

	fmt.Println("....  Updating Logical Interconnect EthernetSetting .....")
	liEthernetSettings := ov.EthernetSettings{Type: "EthernetInterconnectSettingsV4",
		InterconnectType: "Ethernet",
		URI:              utils.NewNstring("/rest/logical-interconnects/d4468f89-4442-4324-9c01-624c7382db2d/ethernetSettings"),
		ID:               "d4468f89-4442-4324-9c01-624c7382db2d"}
	err_ethernet := ovc.UpdateLogicalInterconnectEthernetSettings(liEthernetSettings, id)
	if err_ethernet != nil {
		fmt.Println("Could not update Ethernet Settings of Logical Interconnect", err_ethernet)
	}

	fmt.Println("....  Updating Logical Interconnect EthernetSetting Force.....")
	err_ethernet_force := ovc.UpdateLogicalInterconnectEthernetSettingsForce(liEthernetSettings, id, true)
	if err_ethernet_force != nil {
		fmt.Println("Could not update Ethernet Settings of Logical Interconnect", err_ethernet_force)
	}

	fmt.Println("....  Updating Logical Interconnect Firmware.....")
	liFirmware := ov.Firmware{Command: "Update",
		EthernetActivationDelay: 5,
		EthernetActivationType:  "Parallel",
		FcActivationDelay:       5,
		FcActivationType:        "Parallel",
		Force:                   false,
		SppUri:                  utils.NewNstring("/rest/firmware-drivers/SPP_2018_06_20180709_for_HPE_Synergy_Z7550-96524")}
	err_firmware := ovc.UpdateLogicalInterconnectFirmware(liFirmware, id)
	if err_firmware != nil {
		fmt.Println("Could not update Firmware of Logical Interconnect", err_firmware)
	}

	fmt.Println("....  Updating Logical Interconnect Firmware Force.....")
	err_firmware_force := ovc.UpdateLogicalInterconnectFirmwareForce(liFirmware, id, true)
	if err_firmware_force != nil {
		fmt.Println("Could not update Firmware of Logical Interconnect", err_firmware_force)
	}

	fmt.Println("....  Updating Logical Interconnect InternalNetworks.....")
	var internalNetworks []utils.Nstring
	internalNetworks = append(internalNetworks, utils.NewNstring("/rest/ethernet-networks/a71b9c9e-b044-48ee-8e4e-26ced1a9a9ef"))
	err_networks := ovc.UpdateLogicalInterconnectInternalNetworks(internalNetworks, id)
	if err_networks != nil {
		fmt.Println("Could not update Internal Networks of Logical Interconnect", err_networks)
	}
	fmt.Println("....  Updating Logical Interconnect InternalNetworks Force.....")
	err_networks_force := ovc.UpdateLogicalInterconnectInternalNetworksForce(internalNetworks, id, true)
	if err_networks_force != nil {
		fmt.Println("Could not update Internal Networks of Logical Interconnect", err_networks_force)
	}

	fmt.Println("....  Updating Logical Interconnect QOS Configuration.....")
	liActiveQosConfig := ov.ActiveQosConfig{Type: "QosConfiguration", Category: "qos-aggregated-configuration", ConfigType: "Passthrough"}
	liQosConfig := ov.QosConfiguration{Type: "qos-aggregated-configuration", Category: "qos-aggregated-configuration", ActiveQosConfig: liActiveQosConfig}

	err_qos := ovc.UpdateLogicalInterconnectQosConfigurations(liQosConfig, id)
	if err_qos != nil {
		fmt.Println("Could not update QOS Configuration of Logical Interconnect", err_qos)
	}

	fmt.Println("....  Updating Logical Interconnect SNMP Configuration.....")
	liSNMPConfig := ov.SnmpConfiguration{Type: "snmp-configuration", Category: "snmp-configuration", V3Enabled: newTrue()}

	err_snmp := ovc.UpdateLogicalInterconnectSNMPConfigurations(liSNMPConfig, id)
	if err_snmp != nil {
		fmt.Println("Could not update SNMP Configuration of Logical Interconnect", err_snmp)
	}

	fmt.Println("....  Updating Logical Interconnect Configuration.....")
	err_conf := ovc.UpdateLogicalInterconnectConfigurations(id)
	if err_conf != nil {
		fmt.Println("Could not update Configuration of Logical Interconnect", err_conf)
	}

	fmt.Println("....  Updating Logical Interconnect Port Monitor Configuration.....")
	liPMConfig := ov.PortMonitor{Type: "port-monitor", Category: "port-monitor", ETAG: "8a302a85-ec4d-4214-a3e0-10ef71d28769", Name: "name2095641007-1533682087640"}

	err_pm := ovc.UpdateLogicalInterconnectPortMonitor(liPMConfig, id)
	if err_pm != nil {
		fmt.Println("Could not update PortMonitor Configuration of Logical Interconnect", err_pm)
	}

	fmt.Println("....  Updating Logical Interconnect Telemetry  Configuration.....")
	liTMConfig := ov.TelemetryConfiguration{Type: "telemetry-configuration", EnableTelemetry: newTrue(), SampleInterval: 300, SampleCount: 12, Name: "name771327580-1533682118441"}

	err_tm := ovc.UpdateLogicalInterconnectTelemetryConfigurations(liTMConfig, id, tcId)
	if err_tm != nil {
		fmt.Println("Could not update PortMonitor Configuration of Logical Interconnect", err_tm)
	}

}
<|endoftext|>


<commit_before>package filesys

import (
	"context"
	"fmt"
	"io"
	"math"
	"net/http"
	"os"
	"time"

	"github.com/seaweedfs/fuse"
	"github.com/seaweedfs/fuse/fs"

	"github.com/chrislusf/seaweedfs/weed/filer2"
	"github.com/chrislusf/seaweedfs/weed/glog"
	"github.com/chrislusf/seaweedfs/weed/pb/filer_pb"
)

type FileHandle struct {
	// cache file has been written to
	dirtyPages  *ContinuousDirtyPages
	contentType string
	handle      uint64

	f         *File
	RequestId fuse.RequestID // unique ID for request
	NodeId    fuse.NodeID    // file or directory the request is about
	Uid       uint32         // user ID of process making request
	Gid       uint32         // group ID of process making request

}

func newFileHandle(file *File, uid, gid uint32) *FileHandle {
	fh := &FileHandle{
		f:          file,
		dirtyPages: newDirtyPages(file),
		Uid:        uid,
		Gid:        gid,
	}
	if fh.f.entry != nil {
		fh.f.entry.Attributes.FileSize = filer2.FileSize(fh.f.entry)
	}
	return fh
}

var _ = fs.Handle(&FileHandle{})

// var _ = fs.HandleReadAller(&FileHandle{})
var _ = fs.HandleReader(&FileHandle{})
var _ = fs.HandleFlusher(&FileHandle{})
var _ = fs.HandleWriter(&FileHandle{})
var _ = fs.HandleReleaser(&FileHandle{})

func (fh *FileHandle) Read(ctx context.Context, req *fuse.ReadRequest, resp *fuse.ReadResponse) error {

	glog.V(5).Infof("%s read fh %d: [%d,%d)", fh.f.fullpath(), fh.handle, req.Offset, req.Offset+int64(req.Size))

	buff := make([]byte, req.Size)

	totalRead, err := fh.readFromChunks(buff, req.Offset)
	if err == nil {
		dirtyOffset, dirtySize := fh.readFromDirtyPages(buff, req.Offset)
		if totalRead+req.Offset < dirtyOffset+int64(dirtySize) {
			totalRead = dirtyOffset + int64(dirtySize) - req.Offset
		}
	}

	resp.Data = buff[:totalRead]

	if err != nil {
		glog.Errorf("file handle read %s: %v", fh.f.fullpath(), err)
		return fuse.EIO
	}

	return err
}

func (fh *FileHandle) readFromDirtyPages(buff []byte, startOffset int64) (offset int64, size int) {
	return fh.dirtyPages.ReadDirtyData(buff, startOffset)
}

func (fh *FileHandle) readFromChunks(buff []byte, offset int64) (int64, error) {

	fileSize := int64(filer2.FileSize(fh.f.entry))

	if fileSize == 0 {
		glog.V(1).Infof("empty fh %v", fh.f.fullpath())
		return 0, io.EOF
	}

	var chunkResolveErr error
	if fh.f.entryViewCache == nil {
		fh.f.entryViewCache, chunkResolveErr = filer2.NonOverlappingVisibleIntervals(filer2.LookupFn(fh.f.wfs), fh.f.entry.Chunks)
		if chunkResolveErr != nil {
			return 0, fmt.Errorf("fail to resolve chunk manifest: %v", chunkResolveErr)
		}
		fh.f.reader = nil
	}

	if fh.f.reader == nil {
		chunkViews := filer2.ViewFromVisibleIntervals(fh.f.entryViewCache, 0, math.MaxInt32)
		fh.f.reader = filer2.NewChunkReaderAtFromClient(fh.f.wfs, chunkViews, fh.f.wfs.chunkCache, fileSize)
	}

	totalRead, err := fh.f.reader.ReadAt(buff, offset)

	if err == io.EOF {
		err = nil
	}

	if err != nil {
		glog.Errorf("file handle read %s: %v", fh.f.fullpath(), err)
	}

	// glog.V(0).Infof("file handle read %s [%d,%d] %d : %v", fh.f.fullpath(), offset, offset+int64(totalRead), totalRead, err)

	return int64(totalRead), err
}

// Write to the file handle
func (fh *FileHandle) Write(ctx context.Context, req *fuse.WriteRequest, resp *fuse.WriteResponse) error {

	// write the request to volume servers
	data := make([]byte, len(req.Data))
	copy(data, req.Data)

	fh.f.entry.Attributes.FileSize = uint64(max(req.Offset+int64(len(data)), int64(fh.f.entry.Attributes.FileSize)))
	glog.V(5).Infof("%v write [%d,%d)", fh.f.fullpath(), req.Offset, req.Offset+int64(len(req.Data)))

	chunks, err := fh.dirtyPages.AddPage(req.Offset, data)
	if err != nil {
		glog.Errorf("%v write fh %d: [%d,%d): %v", fh.f.fullpath(), fh.handle, req.Offset, req.Offset+int64(len(data)), err)
		return fuse.EIO
	}

	resp.Size = len(data)

	if req.Offset == 0 {
		// detect mime type
		fh.contentType = http.DetectContentType(data)
		fh.f.dirtyMetadata = true
	}

	if len(chunks) > 0 {

		fh.f.addChunks(chunks)

		fh.f.dirtyMetadata = true
	}

	return nil
}

func (fh *FileHandle) Release(ctx context.Context, req *fuse.ReleaseRequest) error {

	glog.V(4).Infof("Release %v fh %d", fh.f.fullpath(), fh.handle)

	fh.f.isOpen--

	if fh.f.isOpen <= 0 {
		fh.dirtyPages.releaseResource()
		fh.f.wfs.ReleaseHandle(fh.f.fullpath(), fuse.HandleID(fh.handle))
	}
	fh.f.entryViewCache = nil
	fh.f.reader = nil

	return nil
}

func (fh *FileHandle) Flush(ctx context.Context, req *fuse.FlushRequest) error {
	// fflush works at fh level
	// send the data to the OS
	glog.V(5).Infof("Flush %s fh %d %v", fh.f.fullpath(), fh.handle, req)

	chunks, err := fh.dirtyPages.FlushToStorage()
	if err != nil {
		glog.Errorf("flush %s: %v", fh.f.fullpath(), err)
		return fuse.EIO
	}

	if len(chunks) > 0 {
		fh.f.addChunks(chunks)
		fh.f.dirtyMetadata = true
	}

	if !fh.f.dirtyMetadata {
		return nil
	}

	err = fh.f.wfs.WithFilerClient(func(client filer_pb.SeaweedFilerClient) error {

		if fh.f.entry.Attributes != nil {
			fh.f.entry.Attributes.Mime = fh.contentType
			if fh.f.entry.Attributes.Uid == 0 {
				fh.f.entry.Attributes.Uid = req.Uid
			}
			if fh.f.entry.Attributes.Gid == 0 {
				fh.f.entry.Attributes.Gid = req.Gid
			}
			if fh.f.entry.Attributes.Crtime == 0 {
				fh.f.entry.Attributes.Crtime = time.Now().Unix()
			}
			fh.f.entry.Attributes.Mtime = time.Now().Unix()
			fh.f.entry.Attributes.FileMode = uint32(os.FileMode(fh.f.entry.Attributes.FileMode) &^ fh.f.wfs.option.Umask)
			fh.f.entry.Attributes.Collection = fh.dirtyPages.collection
			fh.f.entry.Attributes.Replication = fh.dirtyPages.replication
		}

		request := &filer_pb.CreateEntryRequest{
			Directory: fh.f.dir.FullPath(),
			Entry:     fh.f.entry,
		}

		glog.V(4).Infof("%s set chunks: %v", fh.f.fullpath(), len(fh.f.entry.Chunks))
		for i, chunk := range fh.f.entry.Chunks {
			glog.V(4).Infof("%s chunks %d: %v [%d,%d)", fh.f.fullpath(), i, chunk.GetFileIdString(), chunk.Offset, chunk.Offset+int64(chunk.Size))
		}

		chunks, garbages := filer2.CompactFileChunks(filer2.LookupFn(fh.f.wfs), fh.f.entry.Chunks)
		chunks, manifestErr := filer2.MaybeManifestize(fh.f.wfs.saveDataAsChunk(fh.f.dir.FullPath()), chunks)
		if manifestErr != nil {
			// not good, but should be ok
			glog.V(0).Infof("MaybeManifestize: %v", manifestErr)
		}
		fh.f.entry.Chunks = chunks
		// fh.f.entryViewCache = nil

		// special handling of one chunk md5
		if len(chunks) == 1 {
		}

		if err := filer_pb.CreateEntry(client, request); err != nil {
			glog.Errorf("fh flush create %s: %v", fh.f.fullpath(), err)
			return fmt.Errorf("fh flush create %s: %v", fh.f.fullpath(), err)
		}

		fh.f.wfs.metaCache.InsertEntry(context.Background(), filer2.FromPbEntry(request.Directory, request.Entry))

		fh.f.wfs.deleteFileChunks(garbages)
		for i, chunk := range garbages {
			glog.V(4).Infof("garbage %s chunks %d: %v [%d,%d)", fh.f.fullpath(), i, chunk.GetFileIdString(), chunk.Offset, chunk.Offset+int64(chunk.Size))
		}

		return nil
	})

	if err == nil {
		fh.f.dirtyMetadata = false
	}

	if err != nil {
		glog.Errorf("%v fh %d flush: %v", fh.f.fullpath(), fh.handle, err)
		return fuse.EIO
	}

	return nil
}
<commit_msg>reduce memory allocation<commit_after>package filesys

import (
	"context"
	"fmt"
	"io"
	"math"
	"net/http"
	"os"
	"time"

	"github.com/seaweedfs/fuse"
	"github.com/seaweedfs/fuse/fs"

	"github.com/chrislusf/seaweedfs/weed/filer2"
	"github.com/chrislusf/seaweedfs/weed/glog"
	"github.com/chrislusf/seaweedfs/weed/pb/filer_pb"
)

type FileHandle struct {
	// cache file has been written to
	dirtyPages  *ContinuousDirtyPages
	contentType string
	handle      uint64

	f         *File
	RequestId fuse.RequestID // unique ID for request
	NodeId    fuse.NodeID    // file or directory the request is about
	Uid       uint32         // user ID of process making request
	Gid       uint32         // group ID of process making request

}

func newFileHandle(file *File, uid, gid uint32) *FileHandle {
	fh := &FileHandle{
		f:          file,
		dirtyPages: newDirtyPages(file),
		Uid:        uid,
		Gid:        gid,
	}
	if fh.f.entry != nil {
		fh.f.entry.Attributes.FileSize = filer2.FileSize(fh.f.entry)
	}
	return fh
}

var _ = fs.Handle(&FileHandle{})

// var _ = fs.HandleReadAller(&FileHandle{})
var _ = fs.HandleReader(&FileHandle{})
var _ = fs.HandleFlusher(&FileHandle{})
var _ = fs.HandleWriter(&FileHandle{})
var _ = fs.HandleReleaser(&FileHandle{})

func (fh *FileHandle) Read(ctx context.Context, req *fuse.ReadRequest, resp *fuse.ReadResponse) error {

	glog.V(0).Infof("%s read fh %d: [%d,%d) size %d resp.Data len=%d cap=%d", fh.f.fullpath(), fh.handle, req.Offset, req.Offset+int64(req.Size), req.Size, len(resp.Data), cap(resp.Data))

	buff := resp.Data[:cap(resp.Data)]
	if req.Size > cap(resp.Data) {
		// should not happen
		buff = make([]byte, req.Size)
	}

	totalRead, err := fh.readFromChunks(buff, req.Offset)
	if err == nil {
		dirtyOffset, dirtySize := fh.readFromDirtyPages(buff, req.Offset)
		if totalRead+req.Offset < dirtyOffset+int64(dirtySize) {
			totalRead = dirtyOffset + int64(dirtySize) - req.Offset
		}
	}

	resp.Data = buff[:totalRead]

	if err != nil {
		glog.Errorf("file handle read %s: %v", fh.f.fullpath(), err)
		return fuse.EIO
	}

	return err
}

func (fh *FileHandle) readFromDirtyPages(buff []byte, startOffset int64) (offset int64, size int) {
	return fh.dirtyPages.ReadDirtyData(buff, startOffset)
}

func (fh *FileHandle) readFromChunks(buff []byte, offset int64) (int64, error) {

	fileSize := int64(filer2.FileSize(fh.f.entry))

	if fileSize == 0 {
		glog.V(1).Infof("empty fh %v", fh.f.fullpath())
		return 0, io.EOF
	}

	var chunkResolveErr error
	if fh.f.entryViewCache == nil {
		fh.f.entryViewCache, chunkResolveErr = filer2.NonOverlappingVisibleIntervals(filer2.LookupFn(fh.f.wfs), fh.f.entry.Chunks)
		if chunkResolveErr != nil {
			return 0, fmt.Errorf("fail to resolve chunk manifest: %v", chunkResolveErr)
		}
		fh.f.reader = nil
	}

	if fh.f.reader == nil {
		chunkViews := filer2.ViewFromVisibleIntervals(fh.f.entryViewCache, 0, math.MaxInt32)
		fh.f.reader = filer2.NewChunkReaderAtFromClient(fh.f.wfs, chunkViews, fh.f.wfs.chunkCache, fileSize)
	}

	totalRead, err := fh.f.reader.ReadAt(buff, offset)

	if err == io.EOF {
		err = nil
	}

	if err != nil {
		glog.Errorf("file handle read %s: %v", fh.f.fullpath(), err)
	}

	// glog.V(0).Infof("file handle read %s [%d,%d] %d : %v", fh.f.fullpath(), offset, offset+int64(totalRead), totalRead, err)

	return int64(totalRead), err
}

// Write to the file handle
func (fh *FileHandle) Write(ctx context.Context, req *fuse.WriteRequest, resp *fuse.WriteResponse) error {

	// write the request to volume servers
	data := make([]byte, len(req.Data))
	copy(data, req.Data)

	fh.f.entry.Attributes.FileSize = uint64(max(req.Offset+int64(len(data)), int64(fh.f.entry.Attributes.FileSize)))
	glog.V(5).Infof("%v write [%d,%d)", fh.f.fullpath(), req.Offset, req.Offset+int64(len(req.Data)))

	chunks, err := fh.dirtyPages.AddPage(req.Offset, data)
	if err != nil {
		glog.Errorf("%v write fh %d: [%d,%d): %v", fh.f.fullpath(), fh.handle, req.Offset, req.Offset+int64(len(data)), err)
		return fuse.EIO
	}

	resp.Size = len(data)

	if req.Offset == 0 {
		// detect mime type
		fh.contentType = http.DetectContentType(data)
		fh.f.dirtyMetadata = true
	}

	if len(chunks) > 0 {

		fh.f.addChunks(chunks)

		fh.f.dirtyMetadata = true
	}

	return nil
}

func (fh *FileHandle) Release(ctx context.Context, req *fuse.ReleaseRequest) error {

	glog.V(4).Infof("Release %v fh %d", fh.f.fullpath(), fh.handle)

	fh.f.isOpen--

	if fh.f.isOpen <= 0 {
		fh.dirtyPages.releaseResource()
		fh.f.wfs.ReleaseHandle(fh.f.fullpath(), fuse.HandleID(fh.handle))
	}
	fh.f.entryViewCache = nil
	fh.f.reader = nil

	return nil
}

func (fh *FileHandle) Flush(ctx context.Context, req *fuse.FlushRequest) error {
	// fflush works at fh level
	// send the data to the OS
	glog.V(5).Infof("Flush %s fh %d %v", fh.f.fullpath(), fh.handle, req)

	chunks, err := fh.dirtyPages.FlushToStorage()
	if err != nil {
		glog.Errorf("flush %s: %v", fh.f.fullpath(), err)
		return fuse.EIO
	}

	if len(chunks) > 0 {
		fh.f.addChunks(chunks)
		fh.f.dirtyMetadata = true
	}

	if !fh.f.dirtyMetadata {
		return nil
	}

	err = fh.f.wfs.WithFilerClient(func(client filer_pb.SeaweedFilerClient) error {

		if fh.f.entry.Attributes != nil {
			fh.f.entry.Attributes.Mime = fh.contentType
			if fh.f.entry.Attributes.Uid == 0 {
				fh.f.entry.Attributes.Uid = req.Uid
			}
			if fh.f.entry.Attributes.Gid == 0 {
				fh.f.entry.Attributes.Gid = req.Gid
			}
			if fh.f.entry.Attributes.Crtime == 0 {
				fh.f.entry.Attributes.Crtime = time.Now().Unix()
			}
			fh.f.entry.Attributes.Mtime = time.Now().Unix()
			fh.f.entry.Attributes.FileMode = uint32(os.FileMode(fh.f.entry.Attributes.FileMode) &^ fh.f.wfs.option.Umask)
			fh.f.entry.Attributes.Collection = fh.dirtyPages.collection
			fh.f.entry.Attributes.Replication = fh.dirtyPages.replication
		}

		request := &filer_pb.CreateEntryRequest{
			Directory: fh.f.dir.FullPath(),
			Entry:     fh.f.entry,
		}

		glog.V(4).Infof("%s set chunks: %v", fh.f.fullpath(), len(fh.f.entry.Chunks))
		for i, chunk := range fh.f.entry.Chunks {
			glog.V(4).Infof("%s chunks %d: %v [%d,%d)", fh.f.fullpath(), i, chunk.GetFileIdString(), chunk.Offset, chunk.Offset+int64(chunk.Size))
		}

		chunks, garbages := filer2.CompactFileChunks(filer2.LookupFn(fh.f.wfs), fh.f.entry.Chunks)
		chunks, manifestErr := filer2.MaybeManifestize(fh.f.wfs.saveDataAsChunk(fh.f.dir.FullPath()), chunks)
		if manifestErr != nil {
			// not good, but should be ok
			glog.V(0).Infof("MaybeManifestize: %v", manifestErr)
		}
		fh.f.entry.Chunks = chunks
		// fh.f.entryViewCache = nil

		// special handling of one chunk md5
		if len(chunks) == 1 {
		}

		if err := filer_pb.CreateEntry(client, request); err != nil {
			glog.Errorf("fh flush create %s: %v", fh.f.fullpath(), err)
			return fmt.Errorf("fh flush create %s: %v", fh.f.fullpath(), err)
		}

		fh.f.wfs.metaCache.InsertEntry(context.Background(), filer2.FromPbEntry(request.Directory, request.Entry))

		fh.f.wfs.deleteFileChunks(garbages)
		for i, chunk := range garbages {
			glog.V(4).Infof("garbage %s chunks %d: %v [%d,%d)", fh.f.fullpath(), i, chunk.GetFileIdString(), chunk.Offset, chunk.Offset+int64(chunk.Size))
		}

		return nil
	})

	if err == nil {
		fh.f.dirtyMetadata = false
	}

	if err != nil {
		glog.Errorf("%v fh %d flush: %v", fh.f.fullpath(), fh.handle, err)
		return fuse.EIO
	}

	return nil
}
<|endoftext|>


<commit_before>// Copyright (c) 2012 The gocql Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//This file will be the future home for more policies
package gocql

//RetryableQuery is an interface that represents a query or batch statement that
//exposes the correct functions for the retry policy logic to evaluate correctly.
type RetryableQuery interface {
	Attempts() int
}

// RetryPolicy interace is used by gocql to determine if a query can be attempted
// again after a retryable error has been received. The interface allows gocql
// users to implement their own logic to determine if a query can be attempted
// again.
// See SimpleRetryPolicy as an example of implementing the RetryPolicy interface.
type RetryPolicy interface {
	Attempt(RetryableQuery) bool
}

// SimpleRetryPolicy has simple logic for attempting a query a fixed number of times.
type SimpleRetryPolicy struct {
	NumRetries int //Number of times to retry a query
}

// Attempt tells gocql to attempt the query again based on query.Attemps being less
// than the NumRetries defined in the policy.
func (s *SimpleRetryPolicy) Attempt(q RetryableQuery) bool {
	return q.Attempts() <= s.NumRetries
}
<commit_msg>Fixed spelling error.<commit_after>// Copyright (c) 2012 The gocql Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//This file will be the future home for more policies
package gocql

//RetryableQuery is an interface that represents a query or batch statement that
//exposes the correct functions for the retry policy logic to evaluate correctly.
type RetryableQuery interface {
	Attempts() int
}

// RetryPolicy interace is used by gocql to determine if a query can be attempted
// again after a retryable error has been received. The interface allows gocql
// users to implement their own logic to determine if a query can be attempted
// again.
// See SimpleRetryPolicy as an example of implementing the RetryPolicy interface.
type RetryPolicy interface {
	Attempt(RetryableQuery) bool
}

// SimpleRetryPolicy has simple logic for attempting a query a fixed number of times.
type SimpleRetryPolicy struct {
	NumRetries int //Number of times to retry a query
}

// Attempt tells gocql to attempt the query again based on query.Attempts being less
// than the NumRetries defined in the policy.
func (s *SimpleRetryPolicy) Attempt(q RetryableQuery) bool {
	return q.Attempts() <= s.NumRetries
}
<|endoftext|>


<commit_before>package main

import (
	"os"
	"github.com/urfave/cli"
	"net"
	"sync"
	"strings"
	"strconv"
	log "github.com/Sirupsen/logrus"
	"time"
)

// maxChannels is the maximum number of channels supported
const maxChannels = 4

// timeout is the time before network operations timeout
const timeout = 5 * time.Second

// socketBufferSize is the maximum buffer size for DVR data
const socketBufferSize = 1460

// Config is a struct of all the configuration variables after user input is processed
type Config struct {
	source   *net.TCPAddr // source is the TCPAddr of the DVR
	dest     *net.TCPAddr // dest is the TCPAddr of the server
	user     string       // user is the username to authenticate with the DVR
	pass     string       // pass is the password to authenticate with the DVR
	key      string       // key is the passphrase to authenticate with the server
	channels []int        // channels is an array of currently used channels
	certs    string       // certs is the location to the folder storing client certificates
}

// Flags is a struct of the possible flags for CLI input
type Flags struct {
	user     string
	pass     string
	key      string
	source   string
	dest     string
	channels string
	certs    string
}

// Initialize global variables
var (
	config Config         // config stores the configuration values
	flags  Flags          // flags stores the flag values
	wg     sync.WaitGroup // wg stores the WaitGroup to prevent main.go from halting while routines are running
)

// main defines how the command line application works
func main() {
	// Create a new instance of urfave/cli
	app := cli.NewApp()

	// Each flag is saved in in the global flags variable
	app.Flags = []cli.Flag{
		cli.StringFlag{Name: "user", Value: "", Usage: "Username to authenticate with",
			Destination: &flags.user, EnvVar: "SWANN_USER", },
		cli.StringFlag{Name: "pass", Value: "", Usage: "Password to authenticate with",
			Destination: &flags.pass, EnvVar: "SWANN_PASS", },
		cli.StringFlag{Name: "source", Value: "", Usage: "The address of the DVR in the format host:port",
			Destination: &flags.source, EnvVar: "SWANN_SOURCE", },
		cli.StringFlag{Name: "dest", Value: "", Usage: "The address of the streaming server in the format host:port",
			Destination: &flags.dest, EnvVar: "SWANN_DEST", },
		cli.StringFlag{Name: "key", Value: "", Usage: "Passphrase to authenticate with the server",
			Destination: &flags.key, EnvVar: "SWANN_KEY"},
		cli.StringFlag{Name: "channels", Value: "", Usage: "Channel(s) to stream, delimited by commas",
			Destination: &flags.channels, EnvVar: "SWANN_CHANNELS", },
		cli.StringFlag{Name: "certs", Value: "", Usage: "Absolute file path to the certificate folder",
			Destination: &flags.certs, EnvVar: "SWANN_CERTS", },
	}

	app.Name = "swanntools-client"
	app.Usage = "client for kz/swanntools"
	app.Action = func(c *cli.Context) error {
		// Run the main application
		run()
		return nil
	}

	app.Run(os.Args)
}

// run handles the main running of the application
func run() {
	///////////////////////////////////////
	// 1. Validate and store flag values //
	///////////////////////////////////////

	// Assign empty Config struct to global config variable
	config = Config{}

	// Ensure that the command line flags are not empty
	if flags.user == "" || flags.pass == "" || flags.key == "" || flags.source == "" || flags.dest == "" ||
		flags.channels == "" || flags.certs == "" {
		log.Fatalln("You are missing one or more flags. Run --help for more details.")
	}

	// Add user, pass and key flags to config
	config.user = flags.user
	config.pass = flags.pass
	config.key = flags.key

	// Parse  channel flag string (e.g., "1,3,4" -> ["1", "3", "4"])
	channelSlice := strings.Split(flags.channels, ",")

	// Ensure channels exist
	if len(channelSlice) == 0 {
		log.Fatalln("You must select a channel")
	}

	// Validate each flag
	for i, channel := range channelSlice {
		// Convert channel to integer
		intChannel, err := strconv.Atoi(channel)

		// Ensure maxChannels constraint is kept
		if i >= maxChannels {
			log.Fatalf("You cannot have greater than %d streams", maxChannels)
		} else if err != nil || intChannel > maxChannels {
			log.Fatalf("All channels need to be a number between 1 and %d", maxChannels)
		}

		// Ensure all channels are unique
		if intInSlice(&intChannel, &config.channels) {
			log.Fatalln("All channels need to be unique")
		}

		// Store channel number in config
		config.channels = append(config.channels, intChannel)
	}

	// Ensure certificates exist
	for _, file := range []string{"client.key", "client.pem", "server.pem"} {
		if _, err := os.Stat(flags.certs + "/" + file); err != nil {
			log.Fatalln("Unable to stat certificates: ", err.Error())
		}
	}

	// Store certificates in config
	config.certs = flags.certs

	//////////////////////////////////
	// 2. Resolve the TCP addresses //
	//////////////////////////////////

	// Resolve the source address
	tcpAddr, err := net.ResolveTCPAddr("tcp", flags.source)
	if err != nil {
		log.Fatalln("Resolving the source address failed: ", err.Error())
	}

	// Resolve the destination address
	tcpAddr, err = net.ResolveTCPAddr("tcp", flags.dest)
	if err != nil {
		log.Fatalln("Resolving the destination address failed: ", err.Error())
	}

	// Store addresses in config
	config.source = tcpAddr
	config.dest = tcpAddr

	////////////////////////////////////
	// 3. Retrieve the camera streams //
	////////////////////////////////////

	// Loop through each channel number
	for i := range config.channels {
		// Prevent main from exiting early before goroutines exit
		wg.Add(1)

		// Create a goroutine which streams channel to server
		go Stream{channel: &config.channels[i]}.StreamToServer()
	}

	// Wait for all goroutines to complete before exiting
	wg.Wait()
}
<commit_msg>Clean up constants<commit_after>package main

import (
	"os"
	"github.com/urfave/cli"
	"net"
	"sync"
	"strings"
	"strconv"
	log "github.com/Sirupsen/logrus"
	"time"
)

const (
	maxChannels      = 4               // maxChannels is the maximum number of channels supported
	timeout          = 5 * time.Second // timeout is the time before network operations timeout
	socketBufferSize = 1460            // socketBufferSize is the maximum buffer size for DVR data
)

// Config is a struct of all the configuration variables after user input is processed
type Config struct {
	source   *net.TCPAddr // source is the TCPAddr of the DVR
	dest     *net.TCPAddr // dest is the TCPAddr of the server
	user     string       // user is the username to authenticate with the DVR
	pass     string       // pass is the password to authenticate with the DVR
	key      string       // key is the passphrase to authenticate with the server
	channels []int        // channels is an array of currently used channels
	certs    string       // certs is the location to the folder storing client certificates
}

// Flags is a struct of the possible flags for CLI input
type Flags struct {
	user     string
	pass     string
	key      string
	source   string
	dest     string
	channels string
	certs    string
}

// Initialize global variables
var (
	config Config         // config stores the configuration values
	flags  Flags          // flags stores the flag values
	wg     sync.WaitGroup // wg stores the WaitGroup to prevent main.go from halting while routines are running
)

// main defines how the command line application works
func main() {
	// Create a new instance of urfave/cli
	app := cli.NewApp()

	// Each flag is saved in in the global flags variable
	app.Flags = []cli.Flag{
		cli.StringFlag{Name: "user", Value: "", Usage: "Username to authenticate with",
			Destination: &flags.user, EnvVar: "SWANN_USER", },
		cli.StringFlag{Name: "pass", Value: "", Usage: "Password to authenticate with",
			Destination: &flags.pass, EnvVar: "SWANN_PASS", },
		cli.StringFlag{Name: "source", Value: "", Usage: "The address of the DVR in the format host:port",
			Destination: &flags.source, EnvVar: "SWANN_SOURCE", },
		cli.StringFlag{Name: "dest", Value: "", Usage: "The address of the streaming server in the format host:port",
			Destination: &flags.dest, EnvVar: "SWANN_DEST", },
		cli.StringFlag{Name: "key", Value: "", Usage: "Passphrase to authenticate with the server",
			Destination: &flags.key, EnvVar: "SWANN_KEY"},
		cli.StringFlag{Name: "channels", Value: "", Usage: "Channel(s) to stream, delimited by commas",
			Destination: &flags.channels, EnvVar: "SWANN_CHANNELS", },
		cli.StringFlag{Name: "certs", Value: "", Usage: "Absolute file path to the certificate folder",
			Destination: &flags.certs, EnvVar: "SWANN_CERTS", },
	}

	app.Name = "swanntools-client"
	app.Usage = "client for kz/swanntools"
	app.Action = func(c *cli.Context) error {
		// Run the main application
		run()
		return nil
	}

	app.Run(os.Args)
}

// run handles the main running of the application
func run() {
	///////////////////////////////////////
	// 1. Validate and store flag values //
	///////////////////////////////////////

	// Assign empty Config struct to global config variable
	config = Config{}

	// Ensure that the command line flags are not empty
	if flags.user == "" || flags.pass == "" || flags.key == "" || flags.source == "" || flags.dest == "" ||
		flags.channels == "" || flags.certs == "" {
		log.Fatalln("You are missing one or more flags. Run --help for more details.")
	}

	// Add user, pass and key flags to config
	config.user = flags.user
	config.pass = flags.pass
	config.key = flags.key

	// Parse  channel flag string (e.g., "1,3,4" -> ["1", "3", "4"])
	channelSlice := strings.Split(flags.channels, ",")

	// Ensure channels exist
	if len(channelSlice) == 0 {
		log.Fatalln("You must select a channel")
	}

	// Validate each flag
	for i, channel := range channelSlice {
		// Convert channel to integer
		intChannel, err := strconv.Atoi(channel)

		// Ensure maxChannels constraint is kept
		if i >= maxChannels {
			log.Fatalf("You cannot have greater than %d streams", maxChannels)
		} else if err != nil || intChannel > maxChannels {
			log.Fatalf("All channels need to be a number between 1 and %d", maxChannels)
		}

		// Ensure all channels are unique
		if intInSlice(&intChannel, &config.channels) {
			log.Fatalln("All channels need to be unique")
		}

		// Store channel number in config
		config.channels = append(config.channels, intChannel)
	}

	// Ensure certificates exist
	for _, file := range []string{"client.key", "client.pem", "server.pem"} {
		if _, err := os.Stat(flags.certs + "/" + file); err != nil {
			log.Fatalln("Unable to stat certificates: ", err.Error())
		}
	}

	// Store certificates in config
	config.certs = flags.certs

	//////////////////////////////////
	// 2. Resolve the TCP addresses //
	//////////////////////////////////

	// Resolve the source address
	tcpAddr, err := net.ResolveTCPAddr("tcp", flags.source)
	if err != nil {
		log.Fatalln("Resolving the source address failed: ", err.Error())
	}

	// Resolve the destination address
	tcpAddr, err = net.ResolveTCPAddr("tcp", flags.dest)
	if err != nil {
		log.Fatalln("Resolving the destination address failed: ", err.Error())
	}

	// Store addresses in config
	config.source = tcpAddr
	config.dest = tcpAddr

	////////////////////////////////////
	// 3. Retrieve the camera streams //
	////////////////////////////////////

	// Loop through each channel number
	for i := range config.channels {
		// Prevent main from exiting early before goroutines exit
		wg.Add(1)

		// Create a goroutine which streams channel to server
		go Stream{channel: &config.channels[i]}.StreamToServer()
	}

	// Wait for all goroutines to complete before exiting
	wg.Wait()
}
<|endoftext|>


<commit_before>//session implements a context aware plugin that can add a session id
package session

import (
	"github.com/xtracdev/xavi/plugin"
	"golang.org/x/net/context"
	"math/rand"
	"net/http"
	"time"
)

type sessionKey int

const SessionKey sessionKey = 111

func NewSessionWrapper() plugin.Wrapper {
	return new(SessionWrapper)
}

var seed = rand.NewSource(time.Now().UnixNano())
var gen = rand.New(seed)

type SessionWrapper struct{}

func (lw SessionWrapper) Wrap(h plugin.ContextHandler) plugin.ContextHandler {
	return plugin.ContextHandlerFunc(func(c context.Context, w http.ResponseWriter, r *http.Request) {
		if c == nil {
			c = context.Background()
		}

		c = context.WithValue(c, SessionKey, gen.Intn(999999999))

		h.ServeHTTPContext(c, w, r)
	})
}
<commit_msg>Eliminated rand race condition<commit_after>//session implements a context aware plugin that can add a session id
package session

import (
	"github.com/xtracdev/xavi/plugin"
	"golang.org/x/net/context"
	"math/rand"
	"net/http"
	"time"
	"sync"
)

type sessionKey int

const SessionKey sessionKey = 111

func NewSessionWrapper() plugin.Wrapper {
	return new(SessionWrapper)
}

var mutex sync.Mutex

var seed = rand.NewSource(time.Now().UnixNano())
var gen = rand.New(seed)

type SessionWrapper struct{}

func (lw SessionWrapper) Wrap(h plugin.ContextHandler) plugin.ContextHandler {
	return plugin.ContextHandlerFunc(func(c context.Context, w http.ResponseWriter, r *http.Request) {
		if c == nil {
			c = context.Background()
		}

		mutex.Lock()
		sessionId := gen.Intn(999999999)
		mutex.Unlock()

		c = context.WithValue(c, SessionKey, sessionId)

		h.ServeHTTPContext(c, w, r)
	})
}
<|endoftext|>


<commit_before>package solr

import "testing"

import "fmt"

func TestSolrQueryAddParam(t *testing.T) {

	q := NewQuery()
	q.AddParam("qf", "some qf")

	if q.String() != "qf=some+qf" {
		t.Errorf("Expected to be: 'some qf'")
	}

	fmt.Println(q.String())
}

func TestSolrQueryMultiple(t *testing.T) {
	q := NewQuery()
	q.AddParam("testing", "test")
	s := NewSearch(q)
	q2 := NewQuery()
	q2.AddParam("testing", "testing 2")
	s.AddQuery(q2)
	if s.QueryString() != "testing=test&testing=testing+2" {
		t.Errorf("Expected to be: 'testing=test&testing=testing+2'")
	}
}

func TestSolrQueryRemoveParam(t *testing.T) {
	q := NewQuery()
	q.AddParam("testing", "test")
	q.AddParam("testing2", "testing 2")
	q.RemoveParam("testing2")
	if q.String() != "testing=test" {
		t.Errorf("Expected to be: 'testing=test'")
	}
}
<commit_msg>Adding an extra assertion step before removing param<commit_after>package solr

import "testing"

import "fmt"

func TestSolrQueryAddParam(t *testing.T) {

	q := NewQuery()
	q.AddParam("qf", "some qf")

	if q.String() != "qf=some+qf" {
		t.Errorf("Expected to be: 'some qf'")
	}

	fmt.Println(q.String())
}

func TestSolrSearchMultipleQuery(t *testing.T) {
	q := NewQuery()
	q.AddParam("testing", "test")
	s := NewSearch(q)
	q2 := NewQuery()
	q2.AddParam("testing", "testing 2")
	s.AddQuery(q2)
	if s.QueryString() != "testing=test&testing=testing+2" {
		t.Errorf("Expected to be: 'testing=test&testing=testing+2'")
	}
}

func TestSolrQueryRemoveParam(t *testing.T) {
	q := NewQuery()
	q.AddParam("testing", "test")
	q.AddParam("testing2", "testing 2")
	if q.String() != "testing=test&testing2=testing+2" {
		t.Errorf("Expected to be: 'testing=test&testing2=testing+2'")
	}
	q.RemoveParam("testing2")
	if q.String() != "testing=test" {
		t.Errorf("Expected to be: 'testing=test'")
	}
}
<|endoftext|>