<commit_before>package websession

import (
	"context"
	"fmt"
	"mime"
	"net/http"
	"net/url"

	"zenhack.net/go/sandstorm/capnp/util"
	"zenhack.net/go/sandstorm/capnp/websession"
	"zenhack.net/go/sandstorm/exp/util/bytestream"
	"zenhack.net/go/sandstorm/exp/util/handle"
)

// Parameters common to all websession request methods
type commonParams interface {
	Path() (string, error)
	Context() (websession.WebSession_Context, error)
}

// Our UiSession implementation; this implements WebSession, and holds both the
// SessionData from the new*Session call and the http.Handler to invoke.
type handlerWebSession struct {
	sessionData SessionData
	handler     http.Handler
}

//// Helpers for common parts of request handling ////

// Intialize a request with the data common to all webession request methods.
//
// The request will have a Context that is derived from ctx, but includes the
// SessionData in its Values.
func (h *handlerWebSession) initRequest(ctx context.Context, params commonParams) (*http.Request, error) {
	path, err := params.Path()
	if err != nil {
		return nil, err
	}

	wsCtx, err := params.Context()
	if err != nil {
		return nil, err
	}

	// Sandstorm gives us a path no leading slash, but Go's http library
	// expects one:
	parsedUrl, err := url.ParseRequestURI("/" + path)
	if err != nil {
		return nil, err
	}

	ctx = context.WithValue(ctx, sessionDataKey, h.sessionData)
	req := &http.Request{
		Header: http.Header{},
		URL:    parsedUrl,
	}

	req = req.WithContext(ctx)
	err = copyContextInfo(req, wsCtx)
	if err != nil {
		return nil, err
	}

	return req, nil
}

// Copy the information from the context into the request.
func copyContextInfo(req *http.Request, wsCtx websession.WebSession_Context) error {
	// cookies

	cookies, err := wsCtx.Cookies()
	if err != nil {
		return err
	}
	numCookies := cookies.Len()
	for i := 0; i < numCookies; i++ {
		kv := cookies.At(i)
		key, err := kv.Key()
		if err != nil {
			return err
		}
		val, err := kv.Value()
		if err != nil {
			return err
		}
		req.AddCookie(&http.Cookie{
			Name:  key,
			Value: val,
		})
	}

	// accept

	accept, err := wsCtx.Accept()
	if err != nil {
		return err
	}
	numAccept := accept.Len()
	acceptHeaders := make([]string, numAccept)
	for i := 0; i < numAccept; i++ {
		str, err := formatAccept(accept.At(i))
		if err != nil {
			return err
		}
		acceptHeaders[i] = str
	}
	req.Header["Accept"] = acceptHeaders

	// TODO:
	//
	// acceptEncoding
	// eTagPrecondition
	// additionalHeaders

	return nil
}

// format the argument as expected for the value of the "Accept" header.
func formatAccept(typ websession.WebSession_AcceptedType) (string, error) {
	mimeType, err := typ.MimeType()
	if err != nil {
		return "", err
	}
	param := map[string]string{
		"q": fmt.Sprint(typ.QValue()),
	}
	return mime.FormatMediaType(mimeType, param), nil
}

//// Actual WebSession methods ////

func (h *handlerWebSession) Get(p websession.WebSession_get) error {
	ctx, cancel := handle.WithCancel(p.Ctx)
	req, err := h.initRequest(ctx, p.Params)
	if err != nil {
		return err
	}

	// Just so it's not nil:
	req.Body = http.NoBody

	// TODO: probably factor this out.
	wsCtx, err := p.Params.Context()
	if err != nil {
		return err
	}
	responseStream := wsCtx.ResponseStream()

	if p.Params.IgnoreBody() {
		req.Method = "HEAD"
	} else {
		req.Method = "GET"
	}

	w := &basicResponseWriter{
		statusCode: 0,
		header:     http.Header{},
		cancel:     cancel,
		bodyWriter: bytestream.ToWriteCloser(req.Context(), responseStream),
		response:   p.Results,
	}

	h.handler.ServeHTTP(w, req)
	if w.statusCode == 0 {
		w.WriteHeader(200)
	}
	responseStream.Done(ctx, func(util.ByteStream_done_Params) error {
		return nil
	})
	return nil
}

//// Stubs for unimplemented WebSession methods ////

func (*handlerWebSession) Post(websession.WebSession_post) error     { panic("Not implemented") }
func (*handlerWebSession) Put(websession.WebSession_put) error       { panic("Not implemented") }
func (*handlerWebSession) Delete(websession.WebSession_delete) error { panic("Not implemented") }
func (*handlerWebSession) Patch(websession.WebSession_patch) error   { panic("Not implemented") }
func (*handlerWebSession) PostStreaming(websession.WebSession_postStreaming) error {
	panic("Not implemented")
}
func (*handlerWebSession) PutStreaming(websession.WebSession_putStreaming) error {
	panic("Not implemented")
}
func (*handlerWebSession) OpenWebSocket(websession.WebSession_openWebSocket) error {
	panic("Not implemented")
}
func (*handlerWebSession) Propfind(websession.WebSession_propfind) error   { panic("Not implemented") }
func (*handlerWebSession) Proppatch(websession.WebSession_proppatch) error { panic("Not implemented") }
func (*handlerWebSession) Mkcol(websession.WebSession_mkcol) error         { panic("Not implemented") }
func (*handlerWebSession) Copy(websession.WebSession_copy) error           { panic("Not implemented") }
func (*handlerWebSession) Move(websession.WebSession_move) error           { panic("Not implemented") }
func (*handlerWebSession) Lock(websession.WebSession_lock) error           { panic("Not implemented") }
func (*handlerWebSession) Unlock(websession.WebSession_unlock) error       { panic("Not implemented") }
func (*handlerWebSession) Acl(websession.WebSession_acl) error             { panic("Not implemented") }
func (*handlerWebSession) Report(websession.WebSession_report) error       { panic("Not implemented") }
func (*handlerWebSession) Options(websession.WebSession_options) error     { panic("Not implemented") }
<commit_msg>Return unimplemented exceptions instead of panic.<commit_after>package websession

import (
	"context"
	"fmt"
	"mime"
	"net/http"
	"net/url"

	"zenhack.net/go/sandstorm/capnp/util"
	"zenhack.net/go/sandstorm/capnp/websession"
	"zenhack.net/go/sandstorm/exp/util/bytestream"
	"zenhack.net/go/sandstorm/exp/util/handle"
	"zenhack.net/go/sandstorm/internal/errors"
)

// Parameters common to all websession request methods
type commonParams interface {
	Path() (string, error)
	Context() (websession.WebSession_Context, error)
}

// Our UiSession implementation; this implements WebSession, and holds both the
// SessionData from the new*Session call and the http.Handler to invoke.
type handlerWebSession struct {
	sessionData SessionData
	handler     http.Handler
}

//// Helpers for common parts of request handling ////

// Intialize a request with the data common to all webession request methods.
//
// The request will have a Context that is derived from ctx, but includes the
// SessionData in its Values.
func (h *handlerWebSession) initRequest(ctx context.Context, params commonParams) (*http.Request, error) {
	path, err := params.Path()
	if err != nil {
		return nil, err
	}

	wsCtx, err := params.Context()
	if err != nil {
		return nil, err
	}

	// Sandstorm gives us a path no leading slash, but Go's http library
	// expects one:
	parsedUrl, err := url.ParseRequestURI("/" + path)
	if err != nil {
		return nil, err
	}

	ctx = context.WithValue(ctx, sessionDataKey, h.sessionData)
	req := &http.Request{
		Header: http.Header{},
		URL:    parsedUrl,
	}

	req = req.WithContext(ctx)
	err = copyContextInfo(req, wsCtx)
	if err != nil {
		return nil, err
	}

	return req, nil
}

// Copy the information from the context into the request.
func copyContextInfo(req *http.Request, wsCtx websession.WebSession_Context) error {
	// cookies

	cookies, err := wsCtx.Cookies()
	if err != nil {
		return err
	}
	numCookies := cookies.Len()
	for i := 0; i < numCookies; i++ {
		kv := cookies.At(i)
		key, err := kv.Key()
		if err != nil {
			return err
		}
		val, err := kv.Value()
		if err != nil {
			return err
		}
		req.AddCookie(&http.Cookie{
			Name:  key,
			Value: val,
		})
	}

	// accept

	accept, err := wsCtx.Accept()
	if err != nil {
		return err
	}
	numAccept := accept.Len()
	acceptHeaders := make([]string, numAccept)
	for i := 0; i < numAccept; i++ {
		str, err := formatAccept(accept.At(i))
		if err != nil {
			return err
		}
		acceptHeaders[i] = str
	}
	req.Header["Accept"] = acceptHeaders

	// TODO:
	//
	// acceptEncoding
	// eTagPrecondition
	// additionalHeaders

	return nil
}

// format the argument as expected for the value of the "Accept" header.
func formatAccept(typ websession.WebSession_AcceptedType) (string, error) {
	mimeType, err := typ.MimeType()
	if err != nil {
		return "", err
	}
	param := map[string]string{
		"q": fmt.Sprint(typ.QValue()),
	}
	return mime.FormatMediaType(mimeType, param), nil
}

//// Actual WebSession methods ////

func (h *handlerWebSession) Get(p websession.WebSession_get) error {
	ctx, cancel := handle.WithCancel(p.Ctx)
	req, err := h.initRequest(ctx, p.Params)
	if err != nil {
		return err
	}

	// Just so it's not nil:
	req.Body = http.NoBody

	// TODO: probably factor this out.
	wsCtx, err := p.Params.Context()
	if err != nil {
		return err
	}
	responseStream := wsCtx.ResponseStream()

	if p.Params.IgnoreBody() {
		req.Method = "HEAD"
	} else {
		req.Method = "GET"
	}

	w := &basicResponseWriter{
		statusCode: 0,
		header:     http.Header{},
		cancel:     cancel,
		bodyWriter: bytestream.ToWriteCloser(req.Context(), responseStream),
		response:   p.Results,
	}

	h.handler.ServeHTTP(w, req)
	if w.statusCode == 0 {
		w.WriteHeader(200)
	}
	responseStream.Done(ctx, func(util.ByteStream_done_Params) error {
		return nil
	})
	return nil
}

//// Stubs for unimplemented WebSession methods ////

func (*handlerWebSession) Post(p websession.WebSession_post) error {
	return errors.UnImplementedExn(p.Results.Segment())
}

func (*handlerWebSession) Put(p websession.WebSession_put) error {
	return errors.UnImplementedExn(p.Results.Segment())
}

func (*handlerWebSession) Delete(p websession.WebSession_delete) error {
	return errors.UnImplementedExn(p.Results.Segment())
}

func (*handlerWebSession) Patch(p websession.WebSession_patch) error {
	return errors.UnImplementedExn(p.Results.Segment())
}

func (*handlerWebSession) PostStreaming(p websession.WebSession_postStreaming) error {
	return errors.UnImplementedExn(p.Results.Segment())
}

func (*handlerWebSession) PutStreaming(p websession.WebSession_putStreaming) error {
	return errors.UnImplementedExn(p.Results.Segment())
}

func (*handlerWebSession) OpenWebSocket(p websession.WebSession_openWebSocket) error {
	return errors.UnImplementedExn(p.Results.Segment())
}

func (*handlerWebSession) Propfind(p websession.WebSession_propfind) error {
	return errors.UnImplementedExn(p.Results.Segment())
}

func (*handlerWebSession) Proppatch(p websession.WebSession_proppatch) error {
	return errors.UnImplementedExn(p.Results.Segment())
}

func (*handlerWebSession) Mkcol(p websession.WebSession_mkcol) error {
	return errors.UnImplementedExn(p.Results.Segment())
}

func (*handlerWebSession) Copy(p websession.WebSession_copy) error {
	return errors.UnImplementedExn(p.Results.Segment())
}

func (*handlerWebSession) Move(p websession.WebSession_move) error {
	return errors.UnImplementedExn(p.Results.Segment())
}

func (*handlerWebSession) Lock(p websession.WebSession_lock) error {
	return errors.UnImplementedExn(p.Results.Segment())
}

func (*handlerWebSession) Unlock(p websession.WebSession_unlock) error {
	return errors.UnImplementedExn(p.Results.Segment())
}

func (*handlerWebSession) Acl(p websession.WebSession_acl) error {
	return errors.UnImplementedExn(p.Results.Segment())
}

func (*handlerWebSession) Report(p websession.WebSession_report) error {
	return errors.UnImplementedExn(p.Results.Segment())
}

func (*handlerWebSession) Options(p websession.WebSession_options) error {
	return errors.UnImplementedExn(p.Results.Segment())
}
<|endoftext|>


<commit_before>/*
Copyright 2019 The Kubernetes Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package nodelabel

import (
	"context"
	"fmt"

	v1 "k8s.io/api/core/v1"
	"k8s.io/apimachinery/pkg/labels"
	"k8s.io/apimachinery/pkg/runtime"
	"k8s.io/kubernetes/pkg/scheduler/apis/config"
	"k8s.io/kubernetes/pkg/scheduler/apis/config/validation"
	"k8s.io/kubernetes/pkg/scheduler/framework"
)

// Name of this plugin.
const Name = "NodeLabel"

const (
	// ErrReasonPresenceViolated is used for CheckNodeLabelPresence predicate error.
	ErrReasonPresenceViolated = "node(s) didn't have the requested labels"
)

// New initializes a new plugin and returns it.
func New(plArgs runtime.Object, handle framework.Handle) (framework.Plugin, error) {
	args, err := getArgs(plArgs)
	if err != nil {
		return nil, err
	}
	if err := validation.ValidateNodeLabelArgs(nil, &args); err != nil {
		return nil, err
	}

	return &NodeLabel{
		handle: handle,
		args:   args,
	}, nil
}

func getArgs(obj runtime.Object) (config.NodeLabelArgs, error) {
	ptr, ok := obj.(*config.NodeLabelArgs)
	if !ok {
		return config.NodeLabelArgs{}, fmt.Errorf("want args to be of type NodeLabelArgs, got %T", obj)
	}
	return *ptr, nil
}

// NodeLabel checks whether a pod can fit based on the node labels which match a filter that it requests.
type NodeLabel struct {
	handle framework.Handle
	args   config.NodeLabelArgs
}

var _ framework.FilterPlugin = &NodeLabel{}
var _ framework.ScorePlugin = &NodeLabel{}
var _ framework.EnqueueExtensions = &NodeLabel{}

// Name returns name of the plugin. It is used in logs, etc.
func (pl *NodeLabel) Name() string {
	return Name
}

// Filter invoked at the filter extension point.
// It checks whether all of the specified labels exists on a node or not, regardless of their value
//
// Consider the cases where the nodes are placed in regions/zones/racks and these are identified by labels
// In some cases, it is required that only nodes that are part of ANY of the defined regions/zones/racks be selected
//
// Alternately, eliminating nodes that have a certain label, regardless of value, is also useful
// A node may have a label with "retiring" as key and the date as the value
// and it may be desirable to avoid scheduling new pods on this node.
func (pl *NodeLabel) Filter(ctx context.Context, _ *framework.CycleState, pod *v1.Pod, nodeInfo *framework.NodeInfo) *framework.Status {
	node := nodeInfo.Node()
	if node == nil {
		return framework.NewStatus(framework.Error, "node not found")
	}

	size := int64(len(pl.args.PresentLabels) + len(pl.args.AbsentLabels))
	if size == 0 {
		return nil
	}

	nodeLabels := labels.Set(node.Labels)
	check := func(labels []string, presence bool) bool {
		for _, label := range labels {
			exists := nodeLabels.Has(label)
			if (exists && !presence) || (!exists && presence) {
				return false
			}
		}
		return true
	}
	if check(pl.args.PresentLabels, true) && check(pl.args.AbsentLabels, false) {
		return nil
	}

	return framework.NewStatus(framework.UnschedulableAndUnresolvable, ErrReasonPresenceViolated)
}

// Score invoked at the score extension point.
func (pl *NodeLabel) Score(ctx context.Context, state *framework.CycleState, pod *v1.Pod, nodeName string) (int64, *framework.Status) {
	nodeInfo, err := pl.handle.SnapshotSharedLister().NodeInfos().Get(nodeName)
	if err != nil {
		return 0, framework.AsStatus(fmt.Errorf("getting node %q from Snapshot: %w", nodeName, err))
	}

	node := nodeInfo.Node()

	size := int64(len(pl.args.PresentLabelsPreference) + len(pl.args.AbsentLabelsPreference))
	if size == 0 {
		return 0, nil
	}

	score := int64(0)
	for _, label := range pl.args.PresentLabelsPreference {
		if labels.Set(node.Labels).Has(label) {
			score += framework.MaxNodeScore
		}
	}
	for _, label := range pl.args.AbsentLabelsPreference {
		if !labels.Set(node.Labels).Has(label) {
			score += framework.MaxNodeScore
		}
	}

	// Take average score for each label to ensure the score doesn't exceed MaxNodeScore.
	score /= size

	return score, nil
}

// ScoreExtensions of the Score plugin.
func (pl *NodeLabel) ScoreExtensions() framework.ScoreExtensions {
	return nil
}

// EventsToRegister returns the possible events that may make a Pod
// failed by this plugin schedulable.
func (pl *NodeLabel) EventsToRegister() []framework.ClusterEvent {
	return []framework.ClusterEvent{
		{Resource: framework.Node, ActionType: framework.Add | framework.UpdateNodeLabel},
	}
}
<commit_msg>code cleanup: scheduler simplify the check function in NodeLabel.Filter<commit_after>/*
Copyright 2019 The Kubernetes Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package nodelabel

import (
	"context"
	"fmt"

	v1 "k8s.io/api/core/v1"
	"k8s.io/apimachinery/pkg/labels"
	"k8s.io/apimachinery/pkg/runtime"
	"k8s.io/kubernetes/pkg/scheduler/apis/config"
	"k8s.io/kubernetes/pkg/scheduler/apis/config/validation"
	"k8s.io/kubernetes/pkg/scheduler/framework"
)

// Name of this plugin.
const Name = "NodeLabel"

const (
	// ErrReasonPresenceViolated is used for CheckNodeLabelPresence predicate error.
	ErrReasonPresenceViolated = "node(s) didn't have the requested labels"
)

// New initializes a new plugin and returns it.
func New(plArgs runtime.Object, handle framework.Handle) (framework.Plugin, error) {
	args, err := getArgs(plArgs)
	if err != nil {
		return nil, err
	}
	if err := validation.ValidateNodeLabelArgs(nil, &args); err != nil {
		return nil, err
	}

	return &NodeLabel{
		handle: handle,
		args:   args,
	}, nil
}

func getArgs(obj runtime.Object) (config.NodeLabelArgs, error) {
	ptr, ok := obj.(*config.NodeLabelArgs)
	if !ok {
		return config.NodeLabelArgs{}, fmt.Errorf("want args to be of type NodeLabelArgs, got %T", obj)
	}
	return *ptr, nil
}

// NodeLabel checks whether a pod can fit based on the node labels which match a filter that it requests.
type NodeLabel struct {
	handle framework.Handle
	args   config.NodeLabelArgs
}

var _ framework.FilterPlugin = &NodeLabel{}
var _ framework.ScorePlugin = &NodeLabel{}
var _ framework.EnqueueExtensions = &NodeLabel{}

// Name returns name of the plugin. It is used in logs, etc.
func (pl *NodeLabel) Name() string {
	return Name
}

// Filter invoked at the filter extension point.
// It checks whether all of the specified labels exists on a node or not, regardless of their value
//
// Consider the cases where the nodes are placed in regions/zones/racks and these are identified by labels
// In some cases, it is required that only nodes that are part of ANY of the defined regions/zones/racks be selected
//
// Alternately, eliminating nodes that have a certain label, regardless of value, is also useful
// A node may have a label with "retiring" as key and the date as the value
// and it may be desirable to avoid scheduling new pods on this node.
func (pl *NodeLabel) Filter(ctx context.Context, _ *framework.CycleState, pod *v1.Pod, nodeInfo *framework.NodeInfo) *framework.Status {
	node := nodeInfo.Node()
	if node == nil {
		return framework.NewStatus(framework.Error, "node not found")
	}

	size := int64(len(pl.args.PresentLabels) + len(pl.args.AbsentLabels))
	if size == 0 {
		return nil
	}

	nodeLabels := labels.Set(node.Labels)
	check := func(labels []string, presence bool) bool {
		for _, label := range labels {
			exists := nodeLabels.Has(label)
			if exists != presence {
				return false
			}
		}
		return true
	}
	if check(pl.args.PresentLabels, true) && check(pl.args.AbsentLabels, false) {
		return nil
	}

	return framework.NewStatus(framework.UnschedulableAndUnresolvable, ErrReasonPresenceViolated)
}

// Score invoked at the score extension point.
func (pl *NodeLabel) Score(ctx context.Context, state *framework.CycleState, pod *v1.Pod, nodeName string) (int64, *framework.Status) {
	nodeInfo, err := pl.handle.SnapshotSharedLister().NodeInfos().Get(nodeName)
	if err != nil {
		return 0, framework.AsStatus(fmt.Errorf("getting node %q from Snapshot: %w", nodeName, err))
	}

	node := nodeInfo.Node()

	size := int64(len(pl.args.PresentLabelsPreference) + len(pl.args.AbsentLabelsPreference))
	if size == 0 {
		return 0, nil
	}

	score := int64(0)
	for _, label := range pl.args.PresentLabelsPreference {
		if labels.Set(node.Labels).Has(label) {
			score += framework.MaxNodeScore
		}
	}
	for _, label := range pl.args.AbsentLabelsPreference {
		if !labels.Set(node.Labels).Has(label) {
			score += framework.MaxNodeScore
		}
	}

	// Take average score for each label to ensure the score doesn't exceed MaxNodeScore.
	score /= size

	return score, nil
}

// ScoreExtensions of the Score plugin.
func (pl *NodeLabel) ScoreExtensions() framework.ScoreExtensions {
	return nil
}

// EventsToRegister returns the possible events that may make a Pod
// failed by this plugin schedulable.
func (pl *NodeLabel) EventsToRegister() []framework.ClusterEvent {
	return []framework.ClusterEvent{
		{Resource: framework.Node, ActionType: framework.Add | framework.UpdateNodeLabel},
	}
}
<|endoftext|>


<commit_before>package home

import (
  "github.com/keep94/appcommon/http_util"
  "github.com/keep94/vsafe"
  "github.com/keep94/vsafe/apps/vsafe/common"
  "github.com/keep94/vsafe/vsafedb"
  "html/template"
  "net/http"
  "net/url"
  "strconv"
)

const (
  kRowsAtTop = 3
)

var (
kTemplateSpec = `

  <title>Vsafe using Go</title>
  <link rel="stylesheet" type="text/css" href="/static/theme.css" />
  <link rel="shortcut icon" href="/images/favicon.ico" type="image/x-icon" />

Vsafe using Go for {{.Name}}

<form>
  <input type="text" name="q" value="{{.Get "q"}}" />
  <input type="submit" value="Search" />
</form>
New Entry (Ctrl+Alt+N)

Change password

Sign out

      {{if .Equals "sort" ""}}
        Title
      {{else}}
        Title
      {{end}}

      {{if .Equals "sort" "newest"}}
        Newest First
      {{else}}
        Newest First
      {{end}}

 {{with $top := .}}
 {{range $idx, $element := .Entries}}
  {{if $top.IsCurrent .Id}}

  {{else}}

  {{end}}

      {{if $top.HasAnchor $idx}}{{end}}
      {{.Title}}

    View

    {{if .Desc}}
      {{.Desc}}
    {{else}}

    {{end}}

 {{end}}
 {{end}}

`
)

var (
  kTemplate *template.Template
)

type Handler struct {
  Store vsafedb.EntriesByOwnerRunner
}

func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
  r.ParseForm()
  session := common.GetUserSession(r)
  sortBy := r.Form.Get("sort")
  id, _ := strconv.ParseInt(r.Form.Get("id"), 10, 64)
  entries, err := vsafedb.Entries(h.Store, session.Key().Id, r.Form.Get("q"))
  if err != nil {
    http_util.ReportError(w, "Error reading database", err)
    return
  }
  switch sortBy {
    case "newest":
      vsafedb.Reverse(entries)
    default:
      vsafedb.SortByTitle(entries)
  }
  http_util.WriteTemplate(
      w,
      kTemplate,
      &view{
          Values: http_util.Values{r.Form},
          Name: session.User.Name,
          Entries: entries,
          Url: r.URL,
          Id: id})
}

type view struct {
  http_util.Values
  Name string
  Entries []*vsafe.Entry
  Url *url.URL
  Id int64
}

func (v *view) HasAnchor(idx int) bool {
  return idx + kRowsAtTop < len(v.Entries)
}

func (v *view) Anchor(idx int) int64 {
  return v.Entries[idx + kRowsAtTop].Id
}

func (v *view) EntryLink(id int64) *url.URL {
  return http_util.NewUrl(
      "/vsafe/single",
      "id", strconv.FormatInt(id, 10),
      "prev", v.Url.String())
}

func (v *view) SortBy(sortBy string) *url.URL {
  return http_util.WithParams(
       v.Url,
       "sort", sortBy,
       "id", "0")
}

func (v *view) IsCurrent(id int64) bool {
  return id == v.Id
}

func init() {
  kTemplate = common.NewTemplate("home", kTemplateSpec)
}
<commit_msg>Change rows above highlighted row from 3 to 1.<commit_after>package home

import (
  "github.com/keep94/appcommon/http_util"
  "github.com/keep94/vsafe"
  "github.com/keep94/vsafe/apps/vsafe/common"
  "github.com/keep94/vsafe/vsafedb"
  "html/template"
  "net/http"
  "net/url"
  "strconv"
)

const (
  kRowsAtTop = 1
)

var (
kTemplateSpec = `

  <title>Vsafe using Go</title>
  <link rel="stylesheet" type="text/css" href="/static/theme.css" />
  <link rel="shortcut icon" href="/images/favicon.ico" type="image/x-icon" />

Vsafe using Go for {{.Name}}

<form>
  <input type="text" name="q" value="{{.Get "q"}}" />
  <input type="submit" value="Search" />
</form>
New Entry (Ctrl+Alt+N)

Change password

Sign out

      {{if .Equals "sort" ""}}
        Title
      {{else}}
        Title
      {{end}}

      {{if .Equals "sort" "newest"}}
        Newest First
      {{else}}
        Newest First
      {{end}}

 {{with $top := .}}
 {{range $idx, $element := .Entries}}
  {{if $top.IsCurrent .Id}}

  {{else}}

  {{end}}

      {{if $top.HasAnchor $idx}}{{end}}
      {{.Title}}

    View

    {{if .Desc}}
      {{.Desc}}
    {{else}}

    {{end}}

 {{end}}
 {{end}}

`
)

var (
  kTemplate *template.Template
)

type Handler struct {
  Store vsafedb.EntriesByOwnerRunner
}

func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
  r.ParseForm()
  session := common.GetUserSession(r)
  sortBy := r.Form.Get("sort")
  id, _ := strconv.ParseInt(r.Form.Get("id"), 10, 64)
  entries, err := vsafedb.Entries(h.Store, session.Key().Id, r.Form.Get("q"))
  if err != nil {
    http_util.ReportError(w, "Error reading database", err)
    return
  }
  switch sortBy {
    case "newest":
      vsafedb.Reverse(entries)
    default:
      vsafedb.SortByTitle(entries)
  }
  http_util.WriteTemplate(
      w,
      kTemplate,
      &view{
          Values: http_util.Values{r.Form},
          Name: session.User.Name,
          Entries: entries,
          Url: r.URL,
          Id: id})
}

type view struct {
  http_util.Values
  Name string
  Entries []*vsafe.Entry
  Url *url.URL
  Id int64
}

func (v *view) HasAnchor(idx int) bool {
  return idx + kRowsAtTop < len(v.Entries)
}

func (v *view) Anchor(idx int) int64 {
  return v.Entries[idx + kRowsAtTop].Id
}

func (v *view) EntryLink(id int64) *url.URL {
  return http_util.NewUrl(
      "/vsafe/single",
      "id", strconv.FormatInt(id, 10),
      "prev", v.Url.String())
}

func (v *view) SortBy(sortBy string) *url.URL {
  return http_util.WithParams(
       v.Url,
       "sort", sortBy,
       "id", "0")
}

func (v *view) IsCurrent(id int64) bool {
  return id == v.Id
}

func init() {
  kTemplate = common.NewTemplate("home", kTemplateSpec)
}
<|endoftext|>


<commit_before>/*
Copyright 2014 The Kubernetes Authors All rights reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package priorities

import (
	"math"

	"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
	"github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
	"github.com/GoogleCloudPlatform/kubernetes/plugin/pkg/scheduler/algorithm"
	"github.com/GoogleCloudPlatform/kubernetes/plugin/pkg/scheduler/algorithm/predicates"
	"github.com/golang/glog"
)

// the unused capacity is calculated on a scale of 0-10
// 0 being the lowest priority and 10 being the highest
func calculateScore(requested, capacity int64, node string) int {
	if capacity == 0 {
		return 0
	}
	if requested > capacity {
		glog.Infof("Combined requested resources from existing pods exceeds capacity on minion: %s", node)
		return 0
	}
	return int(((capacity - requested) * 10) / capacity)
}

// Calculate the occupancy on a node.  'node' has information about the resources on the node.
// 'pods' is a list of pods currently scheduled on the node.
func calculateOccupancy(pod *api.Pod, node api.Node, pods []*api.Pod) algorithm.HostPriority {
	totalMilliCPU := int64(0)
	totalMemory := int64(0)
	for _, existingPod := range pods {
		for _, container := range existingPod.Spec.Containers {
			totalMilliCPU += container.Resources.Limits.Cpu().MilliValue()
			totalMemory += container.Resources.Limits.Memory().Value()
		}
	}
	// Add the resources requested by the current pod being scheduled.
	// This also helps differentiate between differently sized, but empty, minions.
	for _, container := range pod.Spec.Containers {
		totalMilliCPU += container.Resources.Limits.Cpu().MilliValue()
		totalMemory += container.Resources.Limits.Memory().Value()
	}

	capacityMilliCPU := node.Status.Capacity.Cpu().MilliValue()
	capacityMemory := node.Status.Capacity.Memory().Value()

	cpuScore := calculateScore(totalMilliCPU, capacityMilliCPU, node.Name)
	memoryScore := calculateScore(totalMemory, capacityMemory, node.Name)
	glog.V(4).Infof(
		"%v -> %v: Least Requested Priority, Absolute/Requested: (%d, %d) / (%d, %d) Score: (%d, %d)",
		pod.Name, node.Name,
		totalMilliCPU, totalMemory,
		capacityMilliCPU, capacityMemory,
		cpuScore, memoryScore,
	)

	return algorithm.HostPriority{
		Host:  node.Name,
		Score: int((cpuScore + memoryScore) / 2),
	}
}

// LeastRequestedPriority is a priority function that favors nodes with fewer requested resources.
// It calculates the percentage of memory and CPU requested by pods scheduled on the node, and prioritizes
// based on the minimum of the average of the fraction of requested to capacity.
// Details: (Sum(requested cpu) / Capacity + Sum(requested memory) / Capacity) * 50
func LeastRequestedPriority(pod *api.Pod, podLister algorithm.PodLister, minionLister algorithm.MinionLister) (algorithm.HostPriorityList, error) {
	nodes, err := minionLister.List()
	if err != nil {
		return algorithm.HostPriorityList{}, err
	}
	podsToMachines, err := predicates.MapPodsToMachines(podLister)

	list := algorithm.HostPriorityList{}
	for _, node := range nodes.Items {
		list = append(list, calculateOccupancy(pod, node, podsToMachines[node.Name]))
	}
	return list, nil
}

type NodeLabelPrioritizer struct {
	label    string
	presence bool
}

func NewNodeLabelPriority(label string, presence bool) algorithm.PriorityFunction {
	labelPrioritizer := &NodeLabelPrioritizer{
		label:    label,
		presence: presence,
	}
	return labelPrioritizer.CalculateNodeLabelPriority
}

// CalculateNodeLabelPriority checks whether a particular label exists on a minion or not, regardless of its value.
// If presence is true, prioritizes minions that have the specified label, regardless of value.
// If presence is false, prioritizes minions that do not have the specified label.
func (n *NodeLabelPrioritizer) CalculateNodeLabelPriority(pod *api.Pod, podLister algorithm.PodLister, minionLister algorithm.MinionLister) (algorithm.HostPriorityList, error) {
	var score int
	minions, err := minionLister.List()
	if err != nil {
		return nil, err
	}

	labeledMinions := map[string]bool{}
	for _, minion := range minions.Items {
		exists := labels.Set(minion.Labels).Has(n.label)
		labeledMinions[minion.Name] = (exists && n.presence) || (!exists && !n.presence)
	}

	result := []algorithm.HostPriority{}
	//score int - scale of 0-10
	// 0 being the lowest priority and 10 being the highest
	for minionName, success := range labeledMinions {
		if success {
			score = 10
		} else {
			score = 0
		}
		result = append(result, algorithm.HostPriority{Host: minionName, Score: score})
	}
	return result, nil
}

// BalancedResourceAllocation favors nodes with balanced resource usage rate.
// BalancedResourceAllocation should **NOT** be used alone, and **MUST** be used together with LeastRequestedPriority.
// It calculates the difference between the cpu and memory fracion of capacity, and prioritizes the host based on how
// close the two metrics are to each other.
// Detail: score = 10 - abs(cpuFraction-memoryFraction)*10. The algorithm is partly inspired by:
// "Wei Huang et al. An Energy Efficient Virtual Machine Placement Algorithm with Balanced Resource Utilization"
func BalancedResourceAllocation(pod *api.Pod, podLister algorithm.PodLister, minionLister algorithm.MinionLister) (algorithm.HostPriorityList, error) {
	nodes, err := minionLister.List()
	if err != nil {
		return algorithm.HostPriorityList{}, err
	}
	podsToMachines, err := predicates.MapPodsToMachines(podLister)

	list := algorithm.HostPriorityList{}
	for _, node := range nodes.Items {
		list = append(list, calculateBalancedResourceAllocation(pod, node, podsToMachines[node.Name]))
	}
	return list, nil
}

func calculateBalancedResourceAllocation(pod *api.Pod, node api.Node, pods []*api.Pod) algorithm.HostPriority {
	totalMilliCPU := int64(0)
	totalMemory := int64(0)
	score := int(0)
	for _, existingPod := range pods {
		for _, container := range existingPod.Spec.Containers {
			totalMilliCPU += container.Resources.Limits.Cpu().MilliValue()
			totalMemory += container.Resources.Limits.Memory().Value()
		}
	}
	// Add the resources requested by the current pod being scheduled.
	// This also helps differentiate between differently sized, but empty, minions.
	for _, container := range pod.Spec.Containers {
		totalMilliCPU += container.Resources.Limits.Cpu().MilliValue()
		totalMemory += container.Resources.Limits.Memory().Value()
	}

	capacityMilliCPU := node.Status.Capacity.Cpu().MilliValue()
	capacityMemory := node.Status.Capacity.Memory().Value()

	cpuFraction := fractionOfCapacity(totalMilliCPU, capacityMilliCPU, node.Name)
	memoryFraction := fractionOfCapacity(totalMemory, capacityMemory, node.Name)
	if cpuFraction >= 1 || memoryFraction >= 1 {
		// if requested >= capacity, the corresponding host should never be preferrred.
		score = 0
	} else {
		// Upper and lower boundary of difference between cpuFraction and memoryFraction are -1 and 1
		// respectively. Multilying the absolute value of the difference by 10 scales the value to
		// 0-10 with 0 representing well balanced allocation and 10 poorly balanced. Subtracting it from
		// 10 leads to the score which also scales from 0 to 10 while 10 representing well balanced.
		diff := math.Abs(cpuFraction - memoryFraction)
		score = int(10 - diff*10)
	}
	glog.V(4).Infof(
		"%v -> %v: Balanced Resource Allocation, Absolute/Requested: (%d, %d) / (%d, %d) Score: (%d)",
		pod.Name, node.Name,
		totalMilliCPU, totalMemory,
		capacityMilliCPU, capacityMemory,
		score,
	)

	return algorithm.HostPriority{
		Host:  node.Name,
		Score: score,
	}
}

func fractionOfCapacity(requested, capacity int64, node string) float64 {
	if capacity == 0 {
		return 1
	}
	return float64(requested) / float64(capacity)
}
<commit_msg>Demote log spam<commit_after>/*
Copyright 2014 The Kubernetes Authors All rights reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package priorities

import (
	"math"

	"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
	"github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
	"github.com/GoogleCloudPlatform/kubernetes/plugin/pkg/scheduler/algorithm"
	"github.com/GoogleCloudPlatform/kubernetes/plugin/pkg/scheduler/algorithm/predicates"
	"github.com/golang/glog"
)

// the unused capacity is calculated on a scale of 0-10
// 0 being the lowest priority and 10 being the highest
func calculateScore(requested, capacity int64, node string) int {
	if capacity == 0 {
		return 0
	}
	if requested > capacity {
		glog.Infof("Combined requested resources from existing pods exceeds capacity on minion: %s", node)
		return 0
	}
	return int(((capacity - requested) * 10) / capacity)
}

// Calculate the occupancy on a node.  'node' has information about the resources on the node.
// 'pods' is a list of pods currently scheduled on the node.
func calculateOccupancy(pod *api.Pod, node api.Node, pods []*api.Pod) algorithm.HostPriority {
	totalMilliCPU := int64(0)
	totalMemory := int64(0)
	for _, existingPod := range pods {
		for _, container := range existingPod.Spec.Containers {
			totalMilliCPU += container.Resources.Limits.Cpu().MilliValue()
			totalMemory += container.Resources.Limits.Memory().Value()
		}
	}
	// Add the resources requested by the current pod being scheduled.
	// This also helps differentiate between differently sized, but empty, minions.
	for _, container := range pod.Spec.Containers {
		totalMilliCPU += container.Resources.Limits.Cpu().MilliValue()
		totalMemory += container.Resources.Limits.Memory().Value()
	}

	capacityMilliCPU := node.Status.Capacity.Cpu().MilliValue()
	capacityMemory := node.Status.Capacity.Memory().Value()

	cpuScore := calculateScore(totalMilliCPU, capacityMilliCPU, node.Name)
	memoryScore := calculateScore(totalMemory, capacityMemory, node.Name)
	glog.V(10).Infof(
		"%v -> %v: Least Requested Priority, Absolute/Requested: (%d, %d) / (%d, %d) Score: (%d, %d)",
		pod.Name, node.Name,
		totalMilliCPU, totalMemory,
		capacityMilliCPU, capacityMemory,
		cpuScore, memoryScore,
	)

	return algorithm.HostPriority{
		Host:  node.Name,
		Score: int((cpuScore + memoryScore) / 2),
	}
}

// LeastRequestedPriority is a priority function that favors nodes with fewer requested resources.
// It calculates the percentage of memory and CPU requested by pods scheduled on the node, and prioritizes
// based on the minimum of the average of the fraction of requested to capacity.
// Details: (Sum(requested cpu) / Capacity + Sum(requested memory) / Capacity) * 50
func LeastRequestedPriority(pod *api.Pod, podLister algorithm.PodLister, minionLister algorithm.MinionLister) (algorithm.HostPriorityList, error) {
	nodes, err := minionLister.List()
	if err != nil {
		return algorithm.HostPriorityList{}, err
	}
	podsToMachines, err := predicates.MapPodsToMachines(podLister)

	list := algorithm.HostPriorityList{}
	for _, node := range nodes.Items {
		list = append(list, calculateOccupancy(pod, node, podsToMachines[node.Name]))
	}
	return list, nil
}

type NodeLabelPrioritizer struct {
	label    string
	presence bool
}

func NewNodeLabelPriority(label string, presence bool) algorithm.PriorityFunction {
	labelPrioritizer := &NodeLabelPrioritizer{
		label:    label,
		presence: presence,
	}
	return labelPrioritizer.CalculateNodeLabelPriority
}

// CalculateNodeLabelPriority checks whether a particular label exists on a minion or not, regardless of its value.
// If presence is true, prioritizes minions that have the specified label, regardless of value.
// If presence is false, prioritizes minions that do not have the specified label.
func (n *NodeLabelPrioritizer) CalculateNodeLabelPriority(pod *api.Pod, podLister algorithm.PodLister, minionLister algorithm.MinionLister) (algorithm.HostPriorityList, error) {
	var score int
	minions, err := minionLister.List()
	if err != nil {
		return nil, err
	}

	labeledMinions := map[string]bool{}
	for _, minion := range minions.Items {
		exists := labels.Set(minion.Labels).Has(n.label)
		labeledMinions[minion.Name] = (exists && n.presence) || (!exists && !n.presence)
	}

	result := []algorithm.HostPriority{}
	//score int - scale of 0-10
	// 0 being the lowest priority and 10 being the highest
	for minionName, success := range labeledMinions {
		if success {
			score = 10
		} else {
			score = 0
		}
		result = append(result, algorithm.HostPriority{Host: minionName, Score: score})
	}
	return result, nil
}

// BalancedResourceAllocation favors nodes with balanced resource usage rate.
// BalancedResourceAllocation should **NOT** be used alone, and **MUST** be used together with LeastRequestedPriority.
// It calculates the difference between the cpu and memory fracion of capacity, and prioritizes the host based on how
// close the two metrics are to each other.
// Detail: score = 10 - abs(cpuFraction-memoryFraction)*10. The algorithm is partly inspired by:
// "Wei Huang et al. An Energy Efficient Virtual Machine Placement Algorithm with Balanced Resource Utilization"
func BalancedResourceAllocation(pod *api.Pod, podLister algorithm.PodLister, minionLister algorithm.MinionLister) (algorithm.HostPriorityList, error) {
	nodes, err := minionLister.List()
	if err != nil {
		return algorithm.HostPriorityList{}, err
	}
	podsToMachines, err := predicates.MapPodsToMachines(podLister)

	list := algorithm.HostPriorityList{}
	for _, node := range nodes.Items {
		list = append(list, calculateBalancedResourceAllocation(pod, node, podsToMachines[node.Name]))
	}
	return list, nil
}

func calculateBalancedResourceAllocation(pod *api.Pod, node api.Node, pods []*api.Pod) algorithm.HostPriority {
	totalMilliCPU := int64(0)
	totalMemory := int64(0)
	score := int(0)
	for _, existingPod := range pods {
		for _, container := range existingPod.Spec.Containers {
			totalMilliCPU += container.Resources.Limits.Cpu().MilliValue()
			totalMemory += container.Resources.Limits.Memory().Value()
		}
	}
	// Add the resources requested by the current pod being scheduled.
	// This also helps differentiate between differently sized, but empty, minions.
	for _, container := range pod.Spec.Containers {
		totalMilliCPU += container.Resources.Limits.Cpu().MilliValue()
		totalMemory += container.Resources.Limits.Memory().Value()
	}

	capacityMilliCPU := node.Status.Capacity.Cpu().MilliValue()
	capacityMemory := node.Status.Capacity.Memory().Value()

	cpuFraction := fractionOfCapacity(totalMilliCPU, capacityMilliCPU, node.Name)
	memoryFraction := fractionOfCapacity(totalMemory, capacityMemory, node.Name)
	if cpuFraction >= 1 || memoryFraction >= 1 {
		// if requested >= capacity, the corresponding host should never be preferrred.
		score = 0
	} else {
		// Upper and lower boundary of difference between cpuFraction and memoryFraction are -1 and 1
		// respectively. Multilying the absolute value of the difference by 10 scales the value to
		// 0-10 with 0 representing well balanced allocation and 10 poorly balanced. Subtracting it from
		// 10 leads to the score which also scales from 0 to 10 while 10 representing well balanced.
		diff := math.Abs(cpuFraction - memoryFraction)
		score = int(10 - diff*10)
	}
	glog.V(10).Infof(
		"%v -> %v: Balanced Resource Allocation, Absolute/Requested: (%d, %d) / (%d, %d) Score: (%d)",
		pod.Name, node.Name,
		totalMilliCPU, totalMemory,
		capacityMilliCPU, capacityMemory,
		score,
	)

	return algorithm.HostPriority{
		Host:  node.Name,
		Score: score,
	}
}

func fractionOfCapacity(requested, capacity int64, node string) float64 {
	if capacity == 0 {
		return 1
	}
	return float64(requested) / float64(capacity)
}
<|endoftext|>


<commit_before>package internal

import (
	"context"
	"fmt"
	"time"

	"github.com/matrix-org/dendrite/federationsender/api"
	"github.com/matrix-org/dendrite/federationsender/internal/perform"
	"github.com/matrix-org/dendrite/roomserver/version"
	"github.com/matrix-org/gomatrixserverlib"
	"github.com/matrix-org/util"
	"github.com/sirupsen/logrus"
)

// PerformLeaveRequest implements api.FederationSenderInternalAPI
func (r *FederationSenderInternalAPI) PerformDirectoryLookup(
	ctx context.Context,
	request *api.PerformDirectoryLookupRequest,
	response *api.PerformDirectoryLookupResponse,
) (err error) {
	dir, err := r.federation.LookupRoomAlias(
		ctx,
		request.ServerName,
		request.RoomAlias,
	)
	if err != nil {
		r.statistics.ForServer(request.ServerName).Failure()
		return err
	}
	response.RoomID = dir.RoomID
	response.ServerNames = dir.Servers
	r.statistics.ForServer(request.ServerName).Success()
	return nil
}

// PerformJoinRequest implements api.FederationSenderInternalAPI
func (r *FederationSenderInternalAPI) PerformJoin(
	ctx context.Context,
	request *api.PerformJoinRequest,
	response *api.PerformJoinResponse,
) (err error) {
	// Look up the supported room versions.
	var supportedVersions []gomatrixserverlib.RoomVersion
	for version := range version.SupportedRoomVersions() {
		supportedVersions = append(supportedVersions, version)
	}

	// Deduplicate the server names we were provided.
	util.SortAndUnique(request.ServerNames)

	// Try each server that we were provided until we land on one that
	// successfully completes the make-join send-join dance.
	for _, serverName := range request.ServerNames {
		// Try to perform a make_join using the information supplied in the
		// request.
		respMakeJoin, err := r.federation.MakeJoin(
			ctx,
			serverName,
			request.RoomID,
			request.UserID,
			supportedVersions,
		)
		if err != nil {
			// TODO: Check if the user was not allowed to join the room.
			r.statistics.ForServer(serverName).Failure()
			return fmt.Errorf("r.federation.MakeJoin: %w", err)
		}

		// Set all the fields to be what they should be, this should be a no-op
		// but it's possible that the remote server returned us something "odd"
		respMakeJoin.JoinEvent.Type = gomatrixserverlib.MRoomMember
		respMakeJoin.JoinEvent.Sender = request.UserID
		respMakeJoin.JoinEvent.StateKey = &request.UserID
		respMakeJoin.JoinEvent.RoomID = request.RoomID
		respMakeJoin.JoinEvent.Redacts = ""
		if request.Content == nil {
			request.Content = map[string]interface{}{}
		}
		request.Content["membership"] = "join"
		if err = respMakeJoin.JoinEvent.SetContent(request.Content); err != nil {
			return fmt.Errorf("respMakeJoin.JoinEvent.SetContent: %w", err)
		}
		if err = respMakeJoin.JoinEvent.SetUnsigned(struct{}{}); err != nil {
			return fmt.Errorf("respMakeJoin.JoinEvent.SetUnsigned: %w", err)
		}

		// Work out if we support the room version that has been supplied in
		// the make_join response.
		if respMakeJoin.RoomVersion == "" {
			respMakeJoin.RoomVersion = gomatrixserverlib.RoomVersionV1
		}
		if _, err = respMakeJoin.RoomVersion.EventFormat(); err != nil {
			return fmt.Errorf("respMakeJoin.RoomVersion.EventFormat: %w", err)
		}

		// Build the join event.
		event, err := respMakeJoin.JoinEvent.Build(
			time.Now(),
			r.cfg.Matrix.ServerName,
			r.cfg.Matrix.KeyID,
			r.cfg.Matrix.PrivateKey,
			respMakeJoin.RoomVersion,
		)
		if err != nil {
			return fmt.Errorf("respMakeJoin.JoinEvent.Build: %w", err)
		}

		// Try to perform a send_join using the newly built event.
		respSendJoin, err := r.federation.SendJoin(
			ctx,
			serverName,
			event,
			respMakeJoin.RoomVersion,
		)
		if err != nil {
			logrus.WithError(err).Warnf("r.federation.SendJoin failed")
			r.statistics.ForServer(serverName).Failure()
			continue
		}

		// Check that the send_join response was valid.
		joinCtx := perform.JoinContext(r.federation, r.keyRing)
		if err = joinCtx.CheckSendJoinResponse(
			ctx, event, serverName, respMakeJoin, respSendJoin,
		); err != nil {
			logrus.WithError(err).Warnf("joinCtx.CheckSendJoinResponse failed")
			continue
		}

		// If we successfully performed a send_join above then the other
		// server now thinks we're a part of the room. Send the newly
		// returned state to the roomserver to update our local view.
		if err = r.producer.SendEventWithState(
			ctx,
			respSendJoin.ToRespState(),
			event.Headered(respMakeJoin.RoomVersion),
		); err != nil {
			logrus.WithError(err).Warnf("r.producer.SendEventWithState failed")
			continue
		}

		// We're all good.
		r.statistics.ForServer(serverName).Success()
		return nil
	}

	// If we reach here then we didn't complete a join for some reason.
	return fmt.Errorf(
		"failed to join user %q to room %q through %d server(s)",
		request.UserID, request.RoomID, len(request.ServerNames),
	)
}

// PerformLeaveRequest implements api.FederationSenderInternalAPI
func (r *FederationSenderInternalAPI) PerformLeave(
	ctx context.Context,
	request *api.PerformLeaveRequest,
	response *api.PerformLeaveResponse,
) (err error) {
	// Deduplicate the server names we were provided.
	util.SortAndUnique(request.ServerNames)

	// Try each server that we were provided until we land on one that
	// successfully completes the make-leave send-leave dance.
	for _, serverName := range request.ServerNames {
		// Try to perform a make_leave using the information supplied in the
		// request.
		respMakeLeave, err := r.federation.MakeLeave(
			ctx,
			serverName,
			request.RoomID,
			request.UserID,
		)
		if err != nil {
			// TODO: Check if the user was not allowed to leave the room.
			logrus.WithError(err).Warnf("r.federation.MakeLeave failed")
			r.statistics.ForServer(serverName).Failure()
			continue
		}

		// Set all the fields to be what they should be, this should be a no-op
		// but it's possible that the remote server returned us something "odd"
		respMakeLeave.LeaveEvent.Type = gomatrixserverlib.MRoomMember
		respMakeLeave.LeaveEvent.Sender = request.UserID
		respMakeLeave.LeaveEvent.StateKey = &request.UserID
		respMakeLeave.LeaveEvent.RoomID = request.RoomID
		respMakeLeave.LeaveEvent.Redacts = ""
		if respMakeLeave.LeaveEvent.Content == nil {
			content := map[string]interface{}{
				"membership": "leave",
			}
			if err = respMakeLeave.LeaveEvent.SetContent(content); err != nil {
				logrus.WithError(err).Warnf("respMakeLeave.LeaveEvent.SetContent failed")
				continue
			}
		}
		if err = respMakeLeave.LeaveEvent.SetUnsigned(struct{}{}); err != nil {
			logrus.WithError(err).Warnf("respMakeLeave.LeaveEvent.SetUnsigned failed")
			continue
		}

		// Work out if we support the room version that has been supplied in
		// the make_leave response.
		if _, err = respMakeLeave.RoomVersion.EventFormat(); err != nil {
			return gomatrixserverlib.UnsupportedRoomVersionError{}
		}

		// Build the leave event.
		event, err := respMakeLeave.LeaveEvent.Build(
			time.Now(),
			r.cfg.Matrix.ServerName,
			r.cfg.Matrix.KeyID,
			r.cfg.Matrix.PrivateKey,
			respMakeLeave.RoomVersion,
		)
		if err != nil {
			logrus.WithError(err).Warnf("respMakeLeave.LeaveEvent.Build failed")
			continue
		}

		// Try to perform a send_leave using the newly built event.
		err = r.federation.SendLeave(
			ctx,
			serverName,
			event,
		)
		if err != nil {
			logrus.WithError(err).Warnf("r.federation.SendLeave failed")
			r.statistics.ForServer(serverName).Failure()
			continue
		}

		r.statistics.ForServer(serverName).Success()
		return nil
	}

	// If we reach here then we didn't complete a leave for some reason.
	return fmt.Errorf(
		"Failed to leave room %q through %d server(s)",
		request.RoomID, len(request.ServerNames),
	)
}
<commit_msg>Don't prematurely stop trying to join using servers (#1041)<commit_after>package internal

import (
	"context"
	"fmt"
	"time"

	"github.com/matrix-org/dendrite/federationsender/api"
	"github.com/matrix-org/dendrite/federationsender/internal/perform"
	"github.com/matrix-org/dendrite/roomserver/version"
	"github.com/matrix-org/gomatrixserverlib"
	"github.com/matrix-org/util"
	"github.com/sirupsen/logrus"
)

// PerformLeaveRequest implements api.FederationSenderInternalAPI
func (r *FederationSenderInternalAPI) PerformDirectoryLookup(
	ctx context.Context,
	request *api.PerformDirectoryLookupRequest,
	response *api.PerformDirectoryLookupResponse,
) (err error) {
	dir, err := r.federation.LookupRoomAlias(
		ctx,
		request.ServerName,
		request.RoomAlias,
	)
	if err != nil {
		r.statistics.ForServer(request.ServerName).Failure()
		return err
	}
	response.RoomID = dir.RoomID
	response.ServerNames = dir.Servers
	r.statistics.ForServer(request.ServerName).Success()
	return nil
}

// PerformJoinRequest implements api.FederationSenderInternalAPI
func (r *FederationSenderInternalAPI) PerformJoin(
	ctx context.Context,
	request *api.PerformJoinRequest,
	response *api.PerformJoinResponse,
) (err error) {
	// Look up the supported room versions.
	var supportedVersions []gomatrixserverlib.RoomVersion
	for version := range version.SupportedRoomVersions() {
		supportedVersions = append(supportedVersions, version)
	}

	// Deduplicate the server names we were provided.
	util.SortAndUnique(request.ServerNames)

	// Try each server that we were provided until we land on one that
	// successfully completes the make-join send-join dance.
	for _, serverName := range request.ServerNames {
		if err := r.performJoinUsingServer(
			ctx,
			request.RoomID,
			request.UserID,
			request.Content,
			serverName,
			supportedVersions,
		); err != nil {
			logrus.WithError(err).WithFields(logrus.Fields{
				"server_name": serverName,
				"room_id":     request.RoomID,
			}).Warnf("Failed to join room through server")
			continue
		}

		// We're all good.
		return nil
	}

	// If we reach here then we didn't complete a join for some reason.
	return fmt.Errorf(
		"failed to join user %q to room %q through %d server(s)",
		request.UserID, request.RoomID, len(request.ServerNames),
	)
}

func (r *FederationSenderInternalAPI) performJoinUsingServer(
	ctx context.Context,
	roomID, userID string,
	content map[string]interface{},
	serverName gomatrixserverlib.ServerName,
	supportedVersions []gomatrixserverlib.RoomVersion,
) error {
	// Try to perform a make_join using the information supplied in the
	// request.
	respMakeJoin, err := r.federation.MakeJoin(
		ctx,
		serverName,
		roomID,
		userID,
		supportedVersions,
	)
	if err != nil {
		// TODO: Check if the user was not allowed to join the room.
		r.statistics.ForServer(serverName).Failure()
		return fmt.Errorf("r.federation.MakeJoin: %w", err)
	}
	r.statistics.ForServer(serverName).Success()

	// Set all the fields to be what they should be, this should be a no-op
	// but it's possible that the remote server returned us something "odd"
	respMakeJoin.JoinEvent.Type = gomatrixserverlib.MRoomMember
	respMakeJoin.JoinEvent.Sender = userID
	respMakeJoin.JoinEvent.StateKey = &userID
	respMakeJoin.JoinEvent.RoomID = roomID
	respMakeJoin.JoinEvent.Redacts = ""
	if content == nil {
		content = map[string]interface{}{}
	}
	content["membership"] = "join"
	if err = respMakeJoin.JoinEvent.SetContent(content); err != nil {
		return fmt.Errorf("respMakeJoin.JoinEvent.SetContent: %w", err)
	}
	if err = respMakeJoin.JoinEvent.SetUnsigned(struct{}{}); err != nil {
		return fmt.Errorf("respMakeJoin.JoinEvent.SetUnsigned: %w", err)
	}

	// Work out if we support the room version that has been supplied in
	// the make_join response.
	if respMakeJoin.RoomVersion == "" {
		respMakeJoin.RoomVersion = gomatrixserverlib.RoomVersionV1
	}
	if _, err = respMakeJoin.RoomVersion.EventFormat(); err != nil {
		return fmt.Errorf("respMakeJoin.RoomVersion.EventFormat: %w", err)
	}

	// Build the join event.
	event, err := respMakeJoin.JoinEvent.Build(
		time.Now(),
		r.cfg.Matrix.ServerName,
		r.cfg.Matrix.KeyID,
		r.cfg.Matrix.PrivateKey,
		respMakeJoin.RoomVersion,
	)
	if err != nil {
		return fmt.Errorf("respMakeJoin.JoinEvent.Build: %w", err)
	}

	// Try to perform a send_join using the newly built event.
	respSendJoin, err := r.federation.SendJoin(
		ctx,
		serverName,
		event,
		respMakeJoin.RoomVersion,
	)
	if err != nil {
		r.statistics.ForServer(serverName).Failure()
		return fmt.Errorf("r.federation.SendJoin: %w", err)
	}
	r.statistics.ForServer(serverName).Success()

	// Check that the send_join response was valid.
	joinCtx := perform.JoinContext(r.federation, r.keyRing)
	if err = joinCtx.CheckSendJoinResponse(
		ctx, event, serverName, respMakeJoin, respSendJoin,
	); err != nil {
		return fmt.Errorf("joinCtx.CheckSendJoinResponse: %w", err)
	}

	// If we successfully performed a send_join above then the other
	// server now thinks we're a part of the room. Send the newly
	// returned state to the roomserver to update our local view.
	if err = r.producer.SendEventWithState(
		ctx,
		respSendJoin.ToRespState(),
		event.Headered(respMakeJoin.RoomVersion),
	); err != nil {
		return fmt.Errorf("r.producer.SendEventWithState: %w", err)
	}

	return nil
}

// PerformLeaveRequest implements api.FederationSenderInternalAPI
func (r *FederationSenderInternalAPI) PerformLeave(
	ctx context.Context,
	request *api.PerformLeaveRequest,
	response *api.PerformLeaveResponse,
) (err error) {
	// Deduplicate the server names we were provided.
	util.SortAndUnique(request.ServerNames)

	// Try each server that we were provided until we land on one that
	// successfully completes the make-leave send-leave dance.
	for _, serverName := range request.ServerNames {
		// Try to perform a make_leave using the information supplied in the
		// request.
		respMakeLeave, err := r.federation.MakeLeave(
			ctx,
			serverName,
			request.RoomID,
			request.UserID,
		)
		if err != nil {
			// TODO: Check if the user was not allowed to leave the room.
			logrus.WithError(err).Warnf("r.federation.MakeLeave failed")
			r.statistics.ForServer(serverName).Failure()
			continue
		}

		// Set all the fields to be what they should be, this should be a no-op
		// but it's possible that the remote server returned us something "odd"
		respMakeLeave.LeaveEvent.Type = gomatrixserverlib.MRoomMember
		respMakeLeave.LeaveEvent.Sender = request.UserID
		respMakeLeave.LeaveEvent.StateKey = &request.UserID
		respMakeLeave.LeaveEvent.RoomID = request.RoomID
		respMakeLeave.LeaveEvent.Redacts = ""
		if respMakeLeave.LeaveEvent.Content == nil {
			content := map[string]interface{}{
				"membership": "leave",
			}
			if err = respMakeLeave.LeaveEvent.SetContent(content); err != nil {
				logrus.WithError(err).Warnf("respMakeLeave.LeaveEvent.SetContent failed")
				continue
			}
		}
		if err = respMakeLeave.LeaveEvent.SetUnsigned(struct{}{}); err != nil {
			logrus.WithError(err).Warnf("respMakeLeave.LeaveEvent.SetUnsigned failed")
			continue
		}

		// Work out if we support the room version that has been supplied in
		// the make_leave response.
		if _, err = respMakeLeave.RoomVersion.EventFormat(); err != nil {
			return gomatrixserverlib.UnsupportedRoomVersionError{}
		}

		// Build the leave event.
		event, err := respMakeLeave.LeaveEvent.Build(
			time.Now(),
			r.cfg.Matrix.ServerName,
			r.cfg.Matrix.KeyID,
			r.cfg.Matrix.PrivateKey,
			respMakeLeave.RoomVersion,
		)
		if err != nil {
			logrus.WithError(err).Warnf("respMakeLeave.LeaveEvent.Build failed")
			continue
		}

		// Try to perform a send_leave using the newly built event.
		err = r.federation.SendLeave(
			ctx,
			serverName,
			event,
		)
		if err != nil {
			logrus.WithError(err).Warnf("r.federation.SendLeave failed")
			r.statistics.ForServer(serverName).Failure()
			continue
		}

		r.statistics.ForServer(serverName).Success()
		return nil
	}

	// If we reach here then we didn't complete a leave for some reason.
	return fmt.Errorf(
		"Failed to leave room %q through %d server(s)",
		request.RoomID, len(request.ServerNames),
	)
}
<|endoftext|>


<commit_before>package seq

import (
	"sync"
	"testing"
	"time"

	"github.com/facebookgo/ensure"
)

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

// NOTE: run these tests with `go test -race -cpu 1,8,32`

func TestSimpleBufSeq_New_BufSize(t *testing.T) {
	ensure.DeepEqual(t, cap(NewSimpleBufSeq(-42).ids), 0)
	ensure.DeepEqual(t, cap(NewSimpleBufSeq(0).ids), 0)
	ensure.DeepEqual(t, cap(NewSimpleBufSeq(1).ids), 1)
	ensure.DeepEqual(t, cap(NewSimpleBufSeq(1e6).ids), int(1e6))
}

func TestSimpleBufSeq_FirstID(t *testing.T) {
	ensure.DeepEqual(t, <-NewSimpleBufSeq(1e2).GetStream(), ID(1))
}

func TestSimpleBufSeq_SingleClient(t *testing.T) {
	seq := NewSimpleBufSeq(1024)
	lastID := ID(0)

	go func() {
		<-time.After(time.Millisecond * 250)
		_ = seq.Close()
	}()

	for id := range seq.GetStream() {
		ensure.DeepEqual(t, id, lastID+1)
		lastID = id
	}
}

func TestSimpleBufSeq_MultiClient(t *testing.T) {
	seq := NewSimpleBufSeq(1024)
	lastID := ID(0)

	go func() {
		<-time.After(time.Millisecond * 250)
		_ = seq.Close()
	}()

	s1, s2, s3 := seq.GetStream(), seq.GetStream(), seq.GetStream()
	for {
		id1 := s1.Next()
		if id1 == 0 {
			break
		}
		ensure.DeepEqual(t, id1, lastID+1)
		lastID++
		id2 := s2.Next()
		if id2 == 0 {
			break
		}
		ensure.DeepEqual(t, id2, id1+1)
		lastID++
		id3 := s3.Next()
		if id3 == 0 {
			break
		}
		ensure.DeepEqual(t, id3, id2+1)
		lastID++
	}
}

func TestSimpleBufSeq_ConcurrentClients256(t *testing.T) {
	seq := NewSimpleBufSeq(1024)

	go func() {
		<-time.After(time.Millisecond * 250)
		_ = seq.Close()
	}()

	wg := &sync.WaitGroup{}
	for i := 0; i < 256; i++ {
		wg.Add(1)
		go func() {
			for id := range seq.GetStream() {
				_ = id
			}
			wg.Done()
		}()
	}
	wg.Wait()
}
<commit_msg>added BenchmarkSimpleBufSeq_BufSize1024_SingleClient<commit_after>package seq

import (
	"sync"
	"testing"
	"time"

	"github.com/facebookgo/ensure"
)

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

// NOTE: run these tests with `go test -race -cpu 1,8,32`

func TestSimpleBufSeq_New_BufSize(t *testing.T) {
	ensure.DeepEqual(t, cap(NewSimpleBufSeq(-42).ids), 0)
	ensure.DeepEqual(t, cap(NewSimpleBufSeq(0).ids), 0)
	ensure.DeepEqual(t, cap(NewSimpleBufSeq(1).ids), 1)
	ensure.DeepEqual(t, cap(NewSimpleBufSeq(1e6).ids), int(1e6))
}

func TestSimpleBufSeq_FirstID(t *testing.T) {
	ensure.DeepEqual(t, <-NewSimpleBufSeq(1e2).GetStream(), ID(1))
}

func TestSimpleBufSeq_SingleClient(t *testing.T) {
	seq := NewSimpleBufSeq(1024)
	lastID := ID(0)

	go func() {
		<-time.After(time.Millisecond * 250)
		_ = seq.Close()
	}()

	for id := range seq.GetStream() {
		ensure.DeepEqual(t, id, lastID+1)
		lastID = id
	}
}

func TestSimpleBufSeq_MultiClient(t *testing.T) {
	seq := NewSimpleBufSeq(1024)
	lastID := ID(0)

	go func() {
		<-time.After(time.Millisecond * 250)
		_ = seq.Close()
	}()

	s1, s2, s3 := seq.GetStream(), seq.GetStream(), seq.GetStream()
	for {
		id1 := s1.Next()
		if id1 == 0 {
			break
		}
		ensure.DeepEqual(t, id1, lastID+1)
		lastID++
		id2 := s2.Next()
		if id2 == 0 {
			break
		}
		ensure.DeepEqual(t, id2, id1+1)
		lastID++
		id3 := s3.Next()
		if id3 == 0 {
			break
		}
		ensure.DeepEqual(t, id3, id2+1)
		lastID++
	}
}

func TestSimpleBufSeq_ConcurrentClients256(t *testing.T) {
	seq := NewSimpleBufSeq(1024)

	go func() {
		<-time.After(time.Millisecond * 250)
		_ = seq.Close()
	}()

	wg := &sync.WaitGroup{}
	for i := 0; i < 256; i++ {
		wg.Add(1)
		go func() {
			for id := range seq.GetStream() {
				_ = id
			}
			wg.Done()
		}()
	}
	wg.Wait()
}

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

// NOTE: run these benchmarks with `go test -bench=. -cpu 1,8,32`

func BenchmarkSimpleBufSeq_BufSize1024_SingleClient(b *testing.B) {
	s := NewSimpleBufSeq(1024).GetStream()
	for i := 0; i < b.N; i++ {
		_ = s.Next()
	}
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"encoding/json"
	"flag"
	"fmt"
	"io/ioutil"
	"net/http"
	"net/url"
	"regexp"
	"strconv"
	"strings"
	"time"
)

var defaultProxyServerPort = 8000
var defaultKodiPort = 8080

var youtube = strings.Replace("{'jsonrpc': '2.0', 'method': 'Player.Open', 'params':{"+
	"'item': {'file':'plugin://plugin.video.youtube/?action="+
	"play_video&videoid=%s'}}, 'id' : 1}", "'", "\"", -1)
var youtubeTime = strings.Replace("{'jsonrpc':'2.0','method':'Player.Open','params':{"+
	"'item':{'file':'plugin://plugin.video.youtube/?action="+
	"play_video&videoid=%s'},"+
	"'options':"+
	"{'resume':{'hours':%d,'minutes':%d,'seconds':%d}}"+
	"},'id':1},", "'", "\"", -1)
var genericUrl = strings.Replace("{'jsonrpc': '2.0', 'method': 'Player.open', 'params': "+
	"{'item': {'file': '%s'}}, 'id': 1}", "'", "\"", -1)

type request struct {
	Url string
}

var kodiPort *int

func main() {
	serverPort := flag.Int("server", defaultProxyServerPort, "Kodi web port")
	kodiPort = flag.Int("kodi", defaultKodiPort, "Proxy server port")
	flag.Parse()

	fmt.Println("Starting server on port", *serverPort)
	http.HandleFunc("/jsonrpc", HandleRpc)
	http.ListenAndServe(fmt.Sprintf(":%d", *serverPort), nil)
}

func divmod(value int64, modulo int64) (int64, int64) {
	mod := (value % modulo)
	return (value - mod) / modulo, mod
}

func generatePayload(video string) string {
	videoId := ""
	data := ""

	if !strings.HasPrefix(video, "http") {
		video = "http://" + video
	}

	// Parse the url
	videoUrl, err := url.Parse(video)
	if err != nil {
		panic(err)
	}

	// Extract video id for youtube
	if regexp.MustCompile("[/\\.]youtube\\.com/").FindString(video) != "" {
		videoId = videoUrl.Query().Get("id")
	} else if regexp.MustCompile("[/\\.]youtu\\.be/").FindString(video) != "" {
		videoId = videoUrl.EscapedPath()[1:]
	} else {
		data = fmt.Sprintf(genericUrl, video)
	}

	if data == "" && videoUrl.Query().Get("t") != "" {
		seek := 0 * time.Second
		timestr := videoUrl.Query().Get("t")

		if value, err := strconv.ParseInt(timestr, 10, 64); err == nil {
			seek = time.Duration(value) * time.Second
		} else {
			seek, _ = time.ParseDuration(videoUrl.Query().Get("t"))
		}

		// go back 15s for viewing convenience
		seek -= 15 * time.Second
		if seek < 0*time.Second {
			seek = 0 * time.Second
		}

		minutes, seconds := divmod(int64(seek.Seconds()), 60)
		hours, minutes := divmod(minutes, 60)

		data = fmt.Sprintf(youtubeTime, videoId, hours, minutes, seconds)
	}

	if data == "" {
		data = fmt.Sprintf(youtube, videoId)
	}

	return data
}

func HandleRpc(w http.ResponseWriter, req *http.Request) {
	s := request{}
	body, err := ioutil.ReadAll(req.Body)

	if err != nil {
		http.Error(w, "", http.StatusInternalServerError)
		return
	}

	err = json.Unmarshal(body, &s)
	if err != nil || s.Url == "" {
		http.Error(w, "", http.StatusBadRequest)
		return
	}

	payload := bytes.NewBufferString(generatePayload(s.Url))
	rsp, err := http.Post(fmt.Sprintf("http://localhost:%d/jsonrpc", *kodiPort), "application/json", payload)
	if err != nil {
		panic(err)
	}

	response, err := ioutil.ReadAll(rsp.Body)
	if err != nil {
		panic(err)
	}

	w.Write(response)
}
<commit_msg>Fix video id extraction<commit_after>package main

import (
	"bytes"
	"encoding/json"
	"flag"
	"fmt"
	"io/ioutil"
	"net/http"
	"net/url"
	"regexp"
	"strconv"
	"strings"
	"time"
)

var defaultProxyServerPort = 8000
var defaultKodiPort = 8080

var youtube = strings.Replace("{'jsonrpc': '2.0', 'method': 'Player.Open', 'params':{"+
	"'item': {'file':'plugin://plugin.video.youtube/?action="+
	"play_video&videoid=%s'}}, 'id' : 1}", "'", "\"", -1)
var youtubeTime = strings.Replace("{'jsonrpc':'2.0','method':'Player.Open','params':{"+
	"'item':{'file':'plugin://plugin.video.youtube/?action="+
	"play_video&videoid=%s'},"+
	"'options':"+
	"{'resume':{'hours':%d,'minutes':%d,'seconds':%d}}"+
	"},'id':1},", "'", "\"", -1)
var genericUrl = strings.Replace("{'jsonrpc': '2.0', 'method': 'Player.open', 'params': "+
	"{'item': {'file': '%s'}}, 'id': 1}", "'", "\"", -1)

type request struct {
	Url string
}

var kodiPort *int

func main() {
	serverPort := flag.Int("server", defaultProxyServerPort, "Kodi web port")
	kodiPort = flag.Int("kodi", defaultKodiPort, "Proxy server port")
	flag.Parse()

	fmt.Println("Starting server on port", *serverPort)
	http.HandleFunc("/jsonrpc", HandleRpc)
	http.ListenAndServe(fmt.Sprintf(":%d", *serverPort), nil)
}

func divmod(value int64, modulo int64) (int64, int64) {
	mod := (value % modulo)
	return (value - mod) / modulo, mod
}

func generatePayload(video string) string {
	videoId := ""
	data := ""

	if !strings.HasPrefix(video, "http") {
		video = "http://" + video
	}

	// Parse the url
	videoUrl, err := url.Parse(video)
	if err != nil {
		panic(err)
	}

	// Extract video id for youtube
	if regexp.MustCompile("[/\\.]youtube\\.com/").FindString(video) != "" {
		videoId = videoUrl.Query().Get("v")
	} else if regexp.MustCompile("[/\\.]youtu\\.be/").FindString(video) != "" {
		videoId = videoUrl.EscapedPath()[1:]
	} else {
		data = fmt.Sprintf(genericUrl, video)
	}

	if data == "" && videoUrl.Query().Get("t") != "" {
		seek := 0 * time.Second
		timestr := videoUrl.Query().Get("t")

		if value, err := strconv.ParseInt(timestr, 10, 64); err == nil {
			seek = time.Duration(value) * time.Second
		} else {
			seek, _ = time.ParseDuration(videoUrl.Query().Get("t"))
		}

		// go back 15s for viewing convenience
		seek -= 15 * time.Second
		if seek < 0*time.Second {
			seek = 0 * time.Second
		}

		minutes, seconds := divmod(int64(seek.Seconds()), 60)
		hours, minutes := divmod(minutes, 60)

		data = fmt.Sprintf(youtubeTime, videoId, hours, minutes, seconds)
	}

	if data == "" {
		data = fmt.Sprintf(youtube, videoId)
	}

	return data
}

func HandleRpc(w http.ResponseWriter, req *http.Request) {
	s := request{}
	body, err := ioutil.ReadAll(req.Body)

	if err != nil {
		http.Error(w, "", http.StatusInternalServerError)
		return
	}

	err = json.Unmarshal(body, &s)
	if err != nil || s.Url == "" {
		http.Error(w, "", http.StatusBadRequest)
		return
	}

	payload := bytes.NewBufferString(generatePayload(s.Url))
	rsp, err := http.Post(fmt.Sprintf("http://localhost:%d/jsonrpc", *kodiPort), "application/json", payload)
	if err != nil {
		panic(err)
	}

	response, err := ioutil.ReadAll(rsp.Body)
	if err != nil {
		panic(err)
	}

	w.Write(response)
}
<|endoftext|>


<commit_before>package rpc

import "github.com/linde12/kod/rpc"

type InputHandler struct {
	ViewID   string
	FilePath string
	C        *Connection
}

func (ih *InputHandler) edit(params Object) {
	params["view_id"] = ih.ViewID
	if _, ok := params["params"]; !ok {
		params["params"] = &rpc.Object{}
	}

	ih.C.Notify(&Request{
		Method: "edit",
		ViewID: ih.ViewID,
		Params: params,
	})
}
func (ih *InputHandler) gesture(params Object) {
	params["view_id"] = ih.ViewID
	if _, ok := params["params"]; !ok {
		params["params"] = &rpc.Object{}
	}

	ih.C.Notify(&Request{
		Method: "gesture",
		ViewID: ih.ViewID,
		Params: params,
	})
}
func (ih *InputHandler) MoveLeft() {
	ih.edit(Object{"method": "move_left"})
}

func (ih *InputHandler) MoveRight() {
	ih.edit(Object{"method": "move_right"})
}

func (ih *InputHandler) MoveUp() {
	ih.edit(Object{"method": "move_up"})
}

func (ih *InputHandler) MoveDown() {
	ih.edit(Object{"method": "move_down"})
}

func (ih *InputHandler) ScrollPageUp() {
	ih.edit(Object{"method": "scroll_page_up"})
}

func (ih *InputHandler) ScrollPageDown() {
	ih.edit(Object{"method": "scroll_page_down"})
}

func (ih *InputHandler) MoveWordLeft() {
	ih.edit(Object{"method": "move_word_left"})
}

func (ih *InputHandler) MoveWordRight() {
	ih.edit(Object{"method": "move_word_right"})
}

func (ih *InputHandler) DeleteBackward() {
	ih.edit(Object{"method": "delete_backward"})
}

func (ih *InputHandler) DeleteForward() {
	ih.edit(Object{"method": "delete_forward"})
}

func (ih *InputHandler) Undo() {
	ih.edit(Object{"method": "undo"})
}

func (ih *InputHandler) Redo() {
	ih.edit(Object{"method": "redo"})
}
func (ih *InputHandler) GoToLine(line int) {
	ih.edit(Object{"method": "goto_line", "params": Object{"line": line}})
}

func (ih *InputHandler) DuplicateLine() {
	ih.edit(Object{"method": "duplicate_line"})
}

func (ih *InputHandler) Tab() {
	ih.edit(Object{"method": "insert_tab"})
}

func (ih *InputHandler) Newline() {
	ih.edit(Object{"method": "insert_newline"})
}

func (ih *InputHandler) Insert(char string) {
	ih.C.Notify(&Request{
		Method: "edit",
		ViewID: ih.ViewID,
		Params: Object{"method": "insert", "params": Object{"chars": char}, "view_id": ih.ViewID},
	})
}

func (ih *InputHandler) Scroll(lineStart, lineEnd int) {
	ih.edit(Object{"method": "scroll", "params": Array{lineStart, lineEnd}})
}

func (ih *InputHandler) Save() {
	ih.C.Notify(&Request{
		Method: "save",
		Params: Object{
			"view_id":   ih.ViewID,
			"file_path": ih.FilePath,
		},
	})
}

func (ih *InputHandler) Click(x, y, mod, clicks int) {
	ih.edit(Object{"method": "click", "params": Array{y, x, mod, clicks}})
}

func (ih *InputHandler) RequestLines(first, last int) {
	ih.edit(Object{"method": "request_lines", "params": Array{first, last}})
}

func (ih *InputHandler) MoveLineUp() {
	//RequestLines//
	//DeleteToBeginningOfLine
	//MoveToRightEndOfLine

}

func (ih *InputHandler) MoveLineDown() {

}
func (ih *InputHandler) Close() {
	ih.C.Notify(&Request{
		Method: "close_view",
		Params: Object{
			"view_id": ih.ViewID,
		},
	})
}
<commit_msg>Remove extra viewid params<commit_after>package rpc

import "github.com/linde12/kod/rpc"

type InputHandler struct {
	ViewID   string
	FilePath string
	C        *Connection
}

func (ih *InputHandler) edit(params Object) {
	params["view_id"] = ih.ViewID
	if _, ok := params["params"]; !ok {
		params["params"] = &rpc.Object{}
	}

	ih.C.Notify(&Request{
		Method: "edit",
		Params: params,
	})
}
func (ih *InputHandler) gesture(params Object) {
	params["view_id"] = ih.ViewID
	if _, ok := params["params"]; !ok {
		params["params"] = &rpc.Object{}
	}

	ih.C.Notify(&Request{
		Method: "gesture",
		Params: params,
	})
}
func (ih *InputHandler) MoveLeft() {
	ih.edit(Object{"method": "move_left"})
}

func (ih *InputHandler) MoveRight() {
	ih.edit(Object{"method": "move_right"})
}

func (ih *InputHandler) MoveUp() {
	ih.edit(Object{"method": "move_up"})
}

func (ih *InputHandler) MoveDown() {
	ih.edit(Object{"method": "move_down"})
}

func (ih *InputHandler) ScrollPageUp() {
	ih.edit(Object{"method": "scroll_page_up"})
}

func (ih *InputHandler) ScrollPageDown() {
	ih.edit(Object{"method": "scroll_page_down"})
}

func (ih *InputHandler) MoveWordLeft() {
	ih.edit(Object{"method": "move_word_left"})
}

func (ih *InputHandler) MoveWordRight() {
	ih.edit(Object{"method": "move_word_right"})
}

func (ih *InputHandler) DeleteBackward() {
	ih.edit(Object{"method": "delete_backward"})
}

func (ih *InputHandler) DeleteForward() {
	ih.edit(Object{"method": "delete_forward"})
}

func (ih *InputHandler) Undo() {
	ih.edit(Object{"method": "undo"})
}

func (ih *InputHandler) Redo() {
	ih.edit(Object{"method": "redo"})
}
func (ih *InputHandler) GoToLine(line int) {
	ih.edit(Object{"method": "goto_line", "params": Object{"line": line}})
}

func (ih *InputHandler) DuplicateLine() {
	ih.edit(Object{"method": "duplicate_line"})
}

func (ih *InputHandler) Tab() {
	ih.edit(Object{"method": "insert_tab"})
}

func (ih *InputHandler) Newline() {
	ih.edit(Object{"method": "insert_newline"})
}

func (ih *InputHandler) Insert(char string) {
	ih.C.Notify(&Request{
		Method: "edit",
		Params: Object{"method": "insert", "params": Object{"chars": char}, "view_id": ih.ViewID},
	})
}

func (ih *InputHandler) Scroll(lineStart, lineEnd int) {
	ih.edit(Object{"method": "scroll", "params": Array{lineStart, lineEnd}})
}

func (ih *InputHandler) Save() {
	ih.C.Notify(&Request{
		Method: "save",
		Params: Object{
			"view_id":   ih.ViewID,
			"file_path": ih.FilePath,
		},
	})
}

func (ih *InputHandler) Click(x, y, mod, clicks int) {
	ih.edit(Object{"method": "click", "params": Array{y, x, mod, clicks}})
}

func (ih *InputHandler) RequestLines(first, last int) {
	ih.edit(Object{"method": "request_lines", "params": Array{first, last}})
}

func (ih *InputHandler) MoveLineUp() {
	//RequestLines//
	//DeleteToBeginningOfLine
	//MoveToRightEndOfLine

}

func (ih *InputHandler) MoveLineDown() {

}
func (ih *InputHandler) Close() {
	ih.C.Notify(&Request{
		Method: "close_view",
		Params: Object{
			"view_id": ih.ViewID,
		},
	})
}
<|endoftext|>


<commit_before>package handlers

import (
	"github.com/go-openapi/runtime/middleware"
	coreclusters "github.com/radanalyticsio/oshinko-cli/core/clusters"
	osa "github.com/radanalyticsio/oshinko-cli/rest/helpers/authentication"
	oe "github.com/radanalyticsio/oshinko-cli/rest/helpers/errors"
	"github.com/radanalyticsio/oshinko-cli/rest/helpers/info"
	"github.com/radanalyticsio/oshinko-cli/rest/models"
	apiclusters "github.com/radanalyticsio/oshinko-cli/rest/restapi/operations/clusters"
)

const nameSpaceMsg = "cannot determine target openshift namespace"
const clientMsg = "unable to create an openshift client"

var codes map[int]int32 = map[int]int32{
	coreclusters.NoCodeAvailable: 500,
	coreclusters.ClusterConfigCode: 409,
	coreclusters.ClientOperationCode: 500,
	coreclusters.ClusterIncompleteCode: 409,
	coreclusters.NoSuchClusterCode: 404,
	coreclusters.ComponentExistsCode: 409,
}

func generalErr(err error, title, msg string, code int32) *models.ErrorResponse {
	if err != nil {
		if msg != "" {
			msg += ", reason: "
		}
		msg += err.Error()
	}
	return oe.NewSingleErrorResponse(code, title, msg)
}

func tostrptr(val string) *string {
	v := val
	return &v
}

func getErrorCode(err error) int32 {

	code := coreclusters.ErrorCode(err)
	if httpcode, ok := codes[code]; ok {
		return httpcode
	}
	return 500

}

func int64ptr(val int) *int64 {
	if val <= coreclusters.SentinelCountValue {
		return nil
	}
	ret := int64(val)
	return &ret
}

func singleClusterResponse(sc coreclusters.SparkCluster) *models.SingleCluster {

	addpod := func(p coreclusters.SparkPod) *models.ClusterModelPodsItems0 {
		pod := new(models.ClusterModelPodsItems0)
		pod.IP = tostrptr(p.IP)
		pod.Status = tostrptr(p.Status)
		pod.Type = tostrptr(p.Type)
		return pod
	}

	// Build the response
	cluster := &models.SingleCluster{&models.ClusterModel{}}
	cluster.Cluster.Name = tostrptr(sc.Name)
	cluster.Cluster.MasterURL = tostrptr(sc.MasterURL)
	cluster.Cluster.MasterWebURL = tostrptr(sc.MasterWebURL)

	cluster.Cluster.Status = tostrptr(sc.Status)

	cluster.Cluster.Pods = []*models.ClusterModelPodsItems0{}
	for i := range sc.Pods {
		cluster.Cluster.Pods = append(cluster.Cluster.Pods, addpod(sc.Pods[i]))
	}

	cluster.Cluster.Config = &models.NewClusterConfig{
		SparkMasterConfig: sc.Config.SparkMasterConfig,
		SparkWorkerConfig: sc.Config.SparkWorkerConfig,
		MasterCount: int64ptr(sc.Config.MasterCount),
		WorkerCount: int64ptr(sc.Config.WorkerCount),
		Name: sc.Config.Name,
	}
	return cluster
}

func getModelCount(val *int64) int {
	if val == nil {
		return coreclusters.SentinelCountValue
	}
	return int(*val)
}

func assignConfig(config *models.NewClusterConfig) *coreclusters.ClusterConfig {
	if config == nil {
		return nil
	}
	result := &coreclusters.ClusterConfig{
		Name: config.Name,
		MasterCount: getModelCount(config.MasterCount),
		WorkerCount: getModelCount(config.WorkerCount),
		SparkMasterConfig: config.SparkMasterConfig,
		SparkWorkerConfig: config.SparkWorkerConfig,
		SparkImage: config.SparkImage,
		ExposeWebUI: config.ExposeWebUI,
	}
	return result
}

// CreateClusterResponse create a cluster and return the representation
func CreateClusterResponse(params apiclusters.CreateClusterParams) middleware.Responder {

	// Do this so that we only have to specify the error code when we build ErrorResponse
	reterr := func(err *models.ErrorResponse) *apiclusters.CreateClusterDefault {
		return apiclusters.NewCreateClusterDefault(int(*err.Errors[0].Status)).WithPayload(err)
	}

	// Convenience wrapper for create failure
	fail := func(err error, msg string, code int32) *models.ErrorResponse {
		return generalErr(err, "cannot create cluster", msg, code)
	}

	const imageMsg = "cannot determine name of spark image"

	clustername := *params.Cluster.Name

	namespace, err := info.GetNamespace()
	if namespace == "" || err != nil {
		return reterr(fail(err, nameSpaceMsg, 500))
	}

	// Even if the image comes back "" at this point, let oshinko-core
	// generate an error. It is possible that the cluster config specifies
	// an image even if no default is set in the environment
	image, err := info.GetSparkImage()
	if err != nil {
		return reterr(fail(err, imageMsg, 500))
	}

	client, err := osa.GetKubeClient()
	if err != nil {
		return reterr(fail(err, clientMsg, 500))
	}

	osclient, err := osa.GetOpenShiftClient()
	if err != nil {
		return reterr(fail(err, clientMsg, 500))
	}

	config := assignConfig(params.Cluster.Config)
	sc, err := coreclusters.CreateCluster(clustername, namespace, image, config, osclient, client)
	if err != nil {
		return reterr(fail(err, "", getErrorCode(err)))
	}
	return apiclusters.NewCreateClusterCreated().WithLocation(sc.Href).WithPayload(singleClusterResponse(sc))
}

// DeleteClusterResponse delete a cluster
func DeleteClusterResponse(params apiclusters.DeleteSingleClusterParams) middleware.Responder {

	// Do this so that we only have to specify the error code when we build ErrorResponse
	reterr := func(err *models.ErrorResponse) *apiclusters.DeleteSingleClusterDefault {
		return apiclusters.NewDeleteSingleClusterDefault(int(*err.Errors[0].Status)).WithPayload(err)
	}

	// Convenience wrapper for delete failure
	fail := func(err error, msg string, code int32) *models.ErrorResponse {
		return generalErr(err, "cluster deletion failed", msg, code)
	}

	namespace, err := info.GetNamespace()
	if namespace == "" || err != nil {
		return reterr(fail(err, nameSpaceMsg, 500))
	}

	osclient, err := osa.GetOpenShiftClient()
	if err != nil {
		return reterr(fail(err, clientMsg, 500))
	}

	client, err := osa.GetKubeClient()
	if err != nil {
		return reterr(fail(err, clientMsg, 500))
	}

	info, err := coreclusters.DeleteCluster(params.Name, namespace, osclient, client)
	if err != nil {
		return reterr(fail(err, "", getErrorCode(err)))
	}
	if info != "" {
		return reterr(fail(nil, "deletion may be incomplete: " + info, 500))
	}
	return apiclusters.NewDeleteSingleClusterNoContent()
}

// FindClustersResponse find a cluster and return its representation
func FindClustersResponse(params apiclusters.FindClustersParams) middleware.Responder {

	// Do this so that we only have to specify the error code when we build ErrorResponse
	reterr := func(err *models.ErrorResponse) *apiclusters.FindClustersDefault {
		return apiclusters.NewFindClustersDefault(int(*err.Errors[0].Status)).WithPayload(err)
	}

	// Convenience wrapper for list failure
	fail := func(err error, msg string, code int32) *models.ErrorResponse {
		return generalErr(err, "cannot list clusters", msg, code)
	}

	namespace, err := info.GetNamespace()
	if namespace == "" || err != nil {
		return reterr(fail(err, nameSpaceMsg, 500))
	}

	client, err := osa.GetKubeClient()
	if err != nil {
		return reterr(fail(err, clientMsg, 500))
	}
	scs, err := coreclusters.FindClusters(namespace, client)
	if err != nil {
		return reterr(fail(err, "", getErrorCode(err)))
	}

	// Create the payload that we're going to write into for the response
	payload := apiclusters.FindClustersOKBodyBody{}
	payload.Clusters = []*apiclusters.ClustersItems0{}
	for idx := range(scs) {
		clt := new(apiclusters.ClustersItems0)
		clt.Href = &scs[idx].Href
		clt.MasterURL = &scs[idx].MasterURL
		clt.MasterWebURL = &scs[idx].MasterWebURL
		clt.Name = &scs[idx].Name
		clt.Status = &scs[idx].Status
		wc := int64(scs[idx].WorkerCount)
		clt.WorkerCount = &wc
		payload.Clusters = append(payload.Clusters, clt)
	}

	return apiclusters.NewFindClustersOK().WithPayload(payload)
}

// FindSingleClusterResponse find a cluster and return its representation
func FindSingleClusterResponse(params apiclusters.FindSingleClusterParams) middleware.Responder {

	clustername := params.Name

	// Do this so that we only have to specify the error code when we build ErrorResponse
	reterr := func(err *models.ErrorResponse) *apiclusters.FindSingleClusterDefault {
		return apiclusters.NewFindSingleClusterDefault(int(*err.Errors[0].Status)).WithPayload(err)
	}

	// Convenience wrapper for get failure
	fail := func(err error, msg string, code int32) *models.ErrorResponse {
		return generalErr(err, "cannot get cluster", msg, code)
	}

	namespace, err := info.GetNamespace()
	if namespace == "" || err != nil {
		return reterr(fail(err, nameSpaceMsg, 500))
	}

	osclient, err := osa.GetOpenShiftClient()
	if err != nil {
		return reterr(fail(err, clientMsg, 500))
	}

	client, err := osa.GetKubeClient()
	if err != nil {
		return reterr(fail(err, clientMsg, 500))
	}

	sc, err := coreclusters.FindSingleCluster(clustername, namespace, osclient, client)
	if err != nil {
		return reterr(fail(err, "", getErrorCode(err)))
	}

	return apiclusters.NewFindSingleClusterOK().WithPayload(singleClusterResponse(sc))
}

// UpdateSingleClusterResponse update a cluster and return the new representation
func UpdateSingleClusterResponse(params apiclusters.UpdateSingleClusterParams) middleware.Responder {

	// Do this so that we only have to specify the error code when we build ErrorResponse
	reterr := func(err *models.ErrorResponse) *apiclusters.UpdateSingleClusterDefault {
		return apiclusters.NewUpdateSingleClusterDefault(int(*err.Errors[0].Status)).WithPayload(err)
	}

	// Convenience wrapper for update failure
	fail := func(err error, msg string, code int32) *models.ErrorResponse {
		return generalErr(err, "cannot update cluster", msg, code)
	}

	const clusterNameMsg = "changing the cluster name is not supported"

	clustername := params.Name

	// Before we do further checks, make sure that we have deploymentconfigs
	// If either the master or the worker deploymentconfig are missing, we
	// assume that the cluster is missing. These are the base objects that
	// we use to create a cluster
	namespace, err := info.GetNamespace()
	if namespace == "" || err != nil {
		return reterr(fail(err, nameSpaceMsg, 500))
	}

	osclient, err := osa.GetOpenShiftClient()
	if err != nil {
		return reterr(fail(err, clientMsg, 500))
	}

	client, err := osa.GetKubeClient()
	if err != nil {
		return reterr(fail(err, clientMsg, 500))
	}

	// Simple things first. At this time we do not support cluster name change and
	// we do not suppport scaling the master count (likely need HA setup for that to make sense)
	if clustername != *params.Cluster.Name {
		return reterr(fail(nil, clusterNameMsg, 409))
	}

	config := assignConfig(params.Cluster.Config)
	sc, err := coreclusters.UpdateCluster(clustername, namespace, config, osclient, client)
	if err != nil {
		return reterr(fail(err, "", getErrorCode(err)))
	}
	return apiclusters.NewUpdateSingleClusterAccepted().WithPayload(singleClusterResponse(sc))
}
<commit_msg>Hoping to get tests passing.<commit_after>package handlers

import (
	"github.com/go-openapi/runtime/middleware"
	coreclusters "github.com/radanalyticsio/oshinko-cli/core/clusters"
	osa "github.com/radanalyticsio/oshinko-cli/rest/helpers/authentication"
	oe "github.com/radanalyticsio/oshinko-cli/rest/helpers/errors"
	"github.com/radanalyticsio/oshinko-cli/rest/helpers/info"
	"github.com/radanalyticsio/oshinko-cli/rest/models"
	apiclusters "github.com/radanalyticsio/oshinko-cli/rest/restapi/operations/clusters"
)

const nameSpaceMsg = "cannot determine target openshift namespace"
const clientMsg = "unable to create an openshift client"

var codes map[int]int32 = map[int]int32{
	coreclusters.NoCodeAvailable: 500,
	coreclusters.ClusterConfigCode: 409,
	coreclusters.ClientOperationCode: 500,
	coreclusters.ClusterIncompleteCode: 409,
	coreclusters.NoSuchClusterCode: 404,
	coreclusters.ComponentExistsCode: 409,
}

func generalErr(err error, title, msg string, code int32) *models.ErrorResponse {
	if err != nil {
		if msg != "" {
			msg += ", reason: "
		}
		msg += err.Error()
	}
	return oe.NewSingleErrorResponse(code, title, msg)
}

func tostrptr(val string) *string {
	v := val
	return &v
}

func getErrorCode(err error) int32 {

	code := coreclusters.ErrorCode(err)
	if httpcode, ok := codes[code]; ok {
		return httpcode
	}
	return 500

}

func int64ptr(val int) *int64 {
	if val <= coreclusters.SentinelCountValue {
		return nil
	}
	ret := int64(val)
	return &ret
}

func singleClusterResponse(sc coreclusters.SparkCluster) *models.SingleCluster {

	addpod := func(p coreclusters.SparkPod) *models.ClusterModelPodsItems0 {
		pod := new(models.ClusterModelPodsItems0)
		pod.IP = tostrptr(p.IP)
		pod.Status = tostrptr(p.Status)
		pod.Type = tostrptr(p.Type)
		return pod
	}

	// Build the response
	cluster := &models.SingleCluster{&models.ClusterModel{}}
	cluster.Cluster.Name = tostrptr(sc.Name)
	cluster.Cluster.MasterURL = tostrptr(sc.MasterURL)
	cluster.Cluster.MasterWebURL = tostrptr(sc.MasterWebURL)

	cluster.Cluster.Status = tostrptr(sc.Status)

	cluster.Cluster.Pods = []*models.ClusterModelPodsItems0{}
	for i := range sc.Pods {
		cluster.Cluster.Pods = append(cluster.Cluster.Pods, addpod(sc.Pods[i]))
	}

	cluster.Cluster.Config = &models.NewClusterConfig{
		SparkMasterConfig: sc.Config.SparkMasterConfig,
		SparkWorkerConfig: sc.Config.SparkWorkerConfig,
		MasterCount: int64ptr(sc.Config.MasterCount),
		WorkerCount: int64ptr(sc.Config.WorkerCount),
		Name: sc.Config.Name,
	}
	return cluster
}

func getModelCount(val *int64) int {
	if val == nil {
		return coreclusters.SentinelCountValue
	}
	return int(*val)
}

func assignConfig(config *models.NewClusterConfig) *coreclusters.ClusterConfig {
	if config == nil {
		return nil
	}
	result := &coreclusters.ClusterConfig{
		Name: config.Name,
		MasterCount: getModelCount(config.MasterCount),
		WorkerCount: getModelCount(config.WorkerCount),
		SparkMasterConfig: config.SparkMasterConfig,
		SparkWorkerConfig: config.SparkWorkerConfig,
		SparkImage: config.SparkImage,
	}
	return result
}

// CreateClusterResponse create a cluster and return the representation
func CreateClusterResponse(params apiclusters.CreateClusterParams) middleware.Responder {

	// Do this so that we only have to specify the error code when we build ErrorResponse
	reterr := func(err *models.ErrorResponse) *apiclusters.CreateClusterDefault {
		return apiclusters.NewCreateClusterDefault(int(*err.Errors[0].Status)).WithPayload(err)
	}

	// Convenience wrapper for create failure
	fail := func(err error, msg string, code int32) *models.ErrorResponse {
		return generalErr(err, "cannot create cluster", msg, code)
	}

	const imageMsg = "cannot determine name of spark image"

	clustername := *params.Cluster.Name

	namespace, err := info.GetNamespace()
	if namespace == "" || err != nil {
		return reterr(fail(err, nameSpaceMsg, 500))
	}

	// Even if the image comes back "" at this point, let oshinko-core
	// generate an error. It is possible that the cluster config specifies
	// an image even if no default is set in the environment
	image, err := info.GetSparkImage()
	if err != nil {
		return reterr(fail(err, imageMsg, 500))
	}

	client, err := osa.GetKubeClient()
	if err != nil {
		return reterr(fail(err, clientMsg, 500))
	}

	osclient, err := osa.GetOpenShiftClient()
	if err != nil {
		return reterr(fail(err, clientMsg, 500))
	}

	config := assignConfig(params.Cluster.Config)
	sc, err := coreclusters.CreateCluster(clustername, namespace, image, config, osclient, client)
	if err != nil {
		return reterr(fail(err, "", getErrorCode(err)))
	}
	return apiclusters.NewCreateClusterCreated().WithLocation(sc.Href).WithPayload(singleClusterResponse(sc))
}

// DeleteClusterResponse delete a cluster
func DeleteClusterResponse(params apiclusters.DeleteSingleClusterParams) middleware.Responder {

	// Do this so that we only have to specify the error code when we build ErrorResponse
	reterr := func(err *models.ErrorResponse) *apiclusters.DeleteSingleClusterDefault {
		return apiclusters.NewDeleteSingleClusterDefault(int(*err.Errors[0].Status)).WithPayload(err)
	}

	// Convenience wrapper for delete failure
	fail := func(err error, msg string, code int32) *models.ErrorResponse {
		return generalErr(err, "cluster deletion failed", msg, code)
	}

	namespace, err := info.GetNamespace()
	if namespace == "" || err != nil {
		return reterr(fail(err, nameSpaceMsg, 500))
	}

	osclient, err := osa.GetOpenShiftClient()
	if err != nil {
		return reterr(fail(err, clientMsg, 500))
	}

	client, err := osa.GetKubeClient()
	if err != nil {
		return reterr(fail(err, clientMsg, 500))
	}

	info, err := coreclusters.DeleteCluster(params.Name, namespace, osclient, client)
	if err != nil {
		return reterr(fail(err, "", getErrorCode(err)))
	}
	if info != "" {
		return reterr(fail(nil, "deletion may be incomplete: " + info, 500))
	}
	return apiclusters.NewDeleteSingleClusterNoContent()
}

// FindClustersResponse find a cluster and return its representation
func FindClustersResponse(params apiclusters.FindClustersParams) middleware.Responder {

	// Do this so that we only have to specify the error code when we build ErrorResponse
	reterr := func(err *models.ErrorResponse) *apiclusters.FindClustersDefault {
		return apiclusters.NewFindClustersDefault(int(*err.Errors[0].Status)).WithPayload(err)
	}

	// Convenience wrapper for list failure
	fail := func(err error, msg string, code int32) *models.ErrorResponse {
		return generalErr(err, "cannot list clusters", msg, code)
	}

	namespace, err := info.GetNamespace()
	if namespace == "" || err != nil {
		return reterr(fail(err, nameSpaceMsg, 500))
	}

	client, err := osa.GetKubeClient()
	if err != nil {
		return reterr(fail(err, clientMsg, 500))
	}
	scs, err := coreclusters.FindClusters(namespace, client)
	if err != nil {
		return reterr(fail(err, "", getErrorCode(err)))
	}

	// Create the payload that we're going to write into for the response
	payload := apiclusters.FindClustersOKBodyBody{}
	payload.Clusters = []*apiclusters.ClustersItems0{}
	for idx := range(scs) {
		clt := new(apiclusters.ClustersItems0)
		clt.Href = &scs[idx].Href
		clt.MasterURL = &scs[idx].MasterURL
		clt.MasterWebURL = &scs[idx].MasterWebURL
		clt.Name = &scs[idx].Name
		clt.Status = &scs[idx].Status
		wc := int64(scs[idx].WorkerCount)
		clt.WorkerCount = &wc
		payload.Clusters = append(payload.Clusters, clt)
	}

	return apiclusters.NewFindClustersOK().WithPayload(payload)
}

// FindSingleClusterResponse find a cluster and return its representation
func FindSingleClusterResponse(params apiclusters.FindSingleClusterParams) middleware.Responder {

	clustername := params.Name

	// Do this so that we only have to specify the error code when we build ErrorResponse
	reterr := func(err *models.ErrorResponse) *apiclusters.FindSingleClusterDefault {
		return apiclusters.NewFindSingleClusterDefault(int(*err.Errors[0].Status)).WithPayload(err)
	}

	// Convenience wrapper for get failure
	fail := func(err error, msg string, code int32) *models.ErrorResponse {
		return generalErr(err, "cannot get cluster", msg, code)
	}

	namespace, err := info.GetNamespace()
	if namespace == "" || err != nil {
		return reterr(fail(err, nameSpaceMsg, 500))
	}

	osclient, err := osa.GetOpenShiftClient()
	if err != nil {
		return reterr(fail(err, clientMsg, 500))
	}

	client, err := osa.GetKubeClient()
	if err != nil {
		return reterr(fail(err, clientMsg, 500))
	}

	sc, err := coreclusters.FindSingleCluster(clustername, namespace, osclient, client)
	if err != nil {
		return reterr(fail(err, "", getErrorCode(err)))
	}

	return apiclusters.NewFindSingleClusterOK().WithPayload(singleClusterResponse(sc))
}

// UpdateSingleClusterResponse update a cluster and return the new representation
func UpdateSingleClusterResponse(params apiclusters.UpdateSingleClusterParams) middleware.Responder {

	// Do this so that we only have to specify the error code when we build ErrorResponse
	reterr := func(err *models.ErrorResponse) *apiclusters.UpdateSingleClusterDefault {
		return apiclusters.NewUpdateSingleClusterDefault(int(*err.Errors[0].Status)).WithPayload(err)
	}

	// Convenience wrapper for update failure
	fail := func(err error, msg string, code int32) *models.ErrorResponse {
		return generalErr(err, "cannot update cluster", msg, code)
	}

	const clusterNameMsg = "changing the cluster name is not supported"

	clustername := params.Name

	// Before we do further checks, make sure that we have deploymentconfigs
	// If either the master or the worker deploymentconfig are missing, we
	// assume that the cluster is missing. These are the base objects that
	// we use to create a cluster
	namespace, err := info.GetNamespace()
	if namespace == "" || err != nil {
		return reterr(fail(err, nameSpaceMsg, 500))
	}

	osclient, err := osa.GetOpenShiftClient()
	if err != nil {
		return reterr(fail(err, clientMsg, 500))
	}

	client, err := osa.GetKubeClient()
	if err != nil {
		return reterr(fail(err, clientMsg, 500))
	}

	// Simple things first. At this time we do not support cluster name change and
	// we do not suppport scaling the master count (likely need HA setup for that to make sense)
	if clustername != *params.Cluster.Name {
		return reterr(fail(nil, clusterNameMsg, 409))
	}

	config := assignConfig(params.Cluster.Config)
	sc, err := coreclusters.UpdateCluster(clustername, namespace, config, osclient, client)
	if err != nil {
		return reterr(fail(err, "", getErrorCode(err)))
	}
	return apiclusters.NewUpdateSingleClusterAccepted().WithPayload(singleClusterResponse(sc))
}
<|endoftext|>