mirror of
https://github.com/harshabose/serve.git
synced 2026-04-22 23:07:27 +08:00
first commit
This commit is contained in:
@@ -0,0 +1,8 @@
|
||||
package client
|
||||
|
||||
import "github.com/coder/websocket"
|
||||
|
||||
type Client struct {
|
||||
id string
|
||||
connection *websocket.Conn
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
package user
|
||||
@@ -0,0 +1,42 @@
|
||||
package interceptor
|
||||
|
||||
type Chain struct {
|
||||
interceptors []Interceptor
|
||||
}
|
||||
|
||||
func CreateChain(interceptors []Interceptor) *Chain {
|
||||
return &Chain{interceptors: interceptors}
|
||||
}
|
||||
|
||||
func (chain *Chain) BindIncoming(reader IncomingReader) IncomingReader {
|
||||
for _, interceptor := range chain.interceptors {
|
||||
interceptor.BindIncoming(reader)
|
||||
}
|
||||
|
||||
return reader
|
||||
}
|
||||
|
||||
func (chain *Chain) BindOutgoing(writer OutgoingWriter) OutgoingWriter {
|
||||
for _, interceptor := range chain.interceptors {
|
||||
interceptor.BindOutgoing(writer)
|
||||
}
|
||||
|
||||
return writer
|
||||
}
|
||||
|
||||
func (chain *Chain) BindConnection(connection Connection) Connection {
|
||||
for _, interceptor := range chain.interceptors {
|
||||
interceptor.BindConnection(connection)
|
||||
}
|
||||
|
||||
return connection
|
||||
}
|
||||
|
||||
func (chain *Chain) Close() error {
|
||||
var errs []error
|
||||
for _, interceptor := range chain.interceptors {
|
||||
errs = append(errs, interceptor.Close())
|
||||
}
|
||||
|
||||
return flattenErrs(errs)
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
package interceptor
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func flattenErrs(errs []error) error {
|
||||
var errs2 []error
|
||||
for _, e := range errs {
|
||||
if e != nil {
|
||||
errs2 = append(errs2, e)
|
||||
}
|
||||
}
|
||||
if len(errs2) == 0 {
|
||||
return nil
|
||||
}
|
||||
return multiError(errs2)
|
||||
}
|
||||
|
||||
type multiError []error
|
||||
|
||||
func (me multiError) Error() string {
|
||||
var errstrings []string
|
||||
|
||||
for _, err := range me {
|
||||
if err != nil {
|
||||
errstrings = append(errstrings, err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
if len(errstrings) == 0 {
|
||||
return "multiError must contain multiple error but is empty"
|
||||
}
|
||||
|
||||
return strings.Join(errstrings, "\n")
|
||||
}
|
||||
|
||||
func (me multiError) Is(err error) bool {
|
||||
for _, e := range me {
|
||||
if errors.Is(e, err) {
|
||||
return true
|
||||
}
|
||||
var me2 multiError
|
||||
if errors.As(e, &me2) {
|
||||
if me2.Is(err) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
package interceptor
|
||||
|
||||
import (
|
||||
"io"
|
||||
|
||||
"github.com/harshabose/skyline_sonata/serve/pkg/message"
|
||||
)
|
||||
|
||||
type Registry struct {
|
||||
factories []Factory
|
||||
}
|
||||
|
||||
func (registry *Registry) Register(factory Factory) {
|
||||
registry.factories = append(registry.factories, factory)
|
||||
}
|
||||
|
||||
func (registry *Registry) Build(id string) (Interceptor, error) {
|
||||
if len(registry.factories) == 0 {
|
||||
return &NoInterceptor{}, nil
|
||||
}
|
||||
|
||||
interceptors := make([]Interceptor, 0)
|
||||
for _, factory := range registry.factories {
|
||||
interceptor, err := factory.NewInterceptor(id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
interceptors = append(interceptors, interceptor)
|
||||
}
|
||||
|
||||
return CreateChain(interceptors), nil
|
||||
}
|
||||
|
||||
// Factory provides an interface for constructing interceptors
|
||||
type Factory interface {
|
||||
NewInterceptor(id string) (Interceptor, error)
|
||||
}
|
||||
|
||||
// Interceptor are transformers which bind to incoming, outgoing and connection of a client of the websocket. This can
|
||||
// be used to add functionalities to the websocket connection.
|
||||
type Interceptor interface {
|
||||
// BindIncoming binds to incoming messages to a client
|
||||
BindIncoming(IncomingReader) IncomingReader
|
||||
|
||||
// BindOutgoing binds to outgoing messages from a client
|
||||
BindOutgoing(OutgoingWriter) OutgoingWriter
|
||||
|
||||
// BindConnection binds to the websocket connection itself
|
||||
BindConnection(Connection) Connection
|
||||
|
||||
io.Closer
|
||||
}
|
||||
|
||||
type IncomingReader interface {
|
||||
Read([]byte) (int, error)
|
||||
}
|
||||
|
||||
type OutgoingWriter interface {
|
||||
Write(message message.BaseMessage) (int, error)
|
||||
}
|
||||
|
||||
type Connection interface {
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package interceptor
|
||||
|
||||
type NoInterceptor struct{}
|
||||
|
||||
func (interceptor *NoInterceptor) BindIncoming(reader IncomingReader) IncomingReader {
|
||||
return reader
|
||||
}
|
||||
|
||||
func (interceptor *NoInterceptor) BindOutgoing(writer OutgoingWriter) OutgoingWriter {
|
||||
return writer
|
||||
}
|
||||
|
||||
func (interceptor *NoInterceptor) BindConnection(connection Connection) Connection {
|
||||
return connection
|
||||
}
|
||||
|
||||
func (interceptor *NoInterceptor) Close() error {
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package message
|
||||
|
||||
type BaseMessage interface {
|
||||
Marshal() ([]byte, error)
|
||||
}
|
||||
|
||||
type Header struct {
|
||||
SourceID string `json:"source_id"`
|
||||
DestinationID string `json:"destination_id"`
|
||||
}
|
||||
|
||||
type Message struct {
|
||||
Header
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
package socket
|
||||
@@ -0,0 +1,3 @@
|
||||
package socket
|
||||
|
||||
type Option = func(*Socket) error
|
||||
@@ -0,0 +1,8 @@
|
||||
package socket
|
||||
|
||||
type Settings struct {
|
||||
}
|
||||
|
||||
func RegisterDefaultSettings(settings *Settings) error {
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
package socket
|
||||
|
||||
import (
|
||||
"github.com/coder/websocket"
|
||||
|
||||
"github.com/harshabose/skyline_sonata/serve/pkg/interceptor"
|
||||
)
|
||||
|
||||
type API struct {
|
||||
settings *Settings
|
||||
interceptorRegistry *interceptor.Registry
|
||||
}
|
||||
|
||||
type APIOption = func(*API) error
|
||||
|
||||
func WithSocketSettings(settings *Settings) APIOption {
|
||||
return func(api *API) error {
|
||||
api.settings = settings
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func WithInterceptorRegistry(registry *interceptor.Registry) APIOption {
|
||||
return func(api *API) error {
|
||||
api.interceptorRegistry = registry
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func CreateSocketFactory(options ...APIOption) (*API, error) {
|
||||
api := &API{
|
||||
settings: nil,
|
||||
interceptorRegistry: nil,
|
||||
}
|
||||
|
||||
for _, option := range options {
|
||||
if err := option(api); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
if api.settings == nil {
|
||||
api.settings = &Settings{}
|
||||
if err := RegisterDefaultSettings(api.settings); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return api, nil
|
||||
}
|
||||
|
||||
func (api *API) CreateWebSocket(id string, options ...Option) (*Socket, error) {
|
||||
socket := &Socket{
|
||||
id: id,
|
||||
}
|
||||
|
||||
interceptors, err := api.interceptorRegistry.Build(id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
socket.interceptor = interceptors
|
||||
|
||||
for _, option := range options {
|
||||
if err := option(socket); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return socket, nil
|
||||
}
|
||||
|
||||
type Socket struct {
|
||||
id string
|
||||
connections map[string]*websocket.Conn
|
||||
interceptor interceptor.Interceptor
|
||||
}
|
||||
|
||||
func (socket *Socket) Serve() {
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user