// NewSockJSHandler returns SockJS handler bind to sockjsPrefix url prefix. // SockJS handler has several handlers inside responsible for various tasks // according to SockJS protocol. func NewSockJSHandler(app *Application, sockjsPrefix, sockjsUrl string) http.Handler { if sockjsUrl != "" { logger.INFO.Println("using SockJS url", sockjsUrl) sockjs.DefaultOptions.SockJSURL = sockjsUrl } return sockjs.NewHandler(sockjsPrefix, sockjs.DefaultOptions, app.sockJSHandler) }
func main() { opts := sockjs.DefaultOptions opts.Websocket = *websocket handler := sockjs.NewHandler("/echo", opts, echoHandler) http.Handle("/echo/", handler) http.Handle("/", http.FileServer(http.Dir("web/"))) log.Println("Server started on port: 8080") log.Fatal(http.ListenAndServe(":8080", nil)) }
func main() { fs := http.FileServer(http.Dir("../static")) http.Handle("/", fs) http.Handle("/ws/", sockjs.NewHandler("/ws", sockjs.DefaultOptions, wsHandler)) log.Println("Listening...") go func() { poll() }() http.ListenAndServe("0.0.0.0:3000", nil) }
func (s *server) configure() { s.sockjs = NewSockJS() s.mux = mux.NewRouter() s.sockjs.AddHandler("connect", s.HandleConnect) s.sockjs.AddHandler("containers", s.HandleContainers) s.sockjs.AddHandler("status", s.HandleStatus) s.sockjs.AddHandler("deploy", s.HandleDeploy) // socket s.mux.Path("/socket/{any:.*}").Handler(sockjs.NewHandler("/socket", sockjs.DefaultOptions, func(session sockjs.Session) { s.sockjs.AddSessionAndRead(session) })) // logged-user s.mux.Path("/rest/user").Methods("GET").HandlerFunc( func(w http.ResponseWriter, r *http.Request) { user, _ := s.oauth.getValidUser(s.oauth.getToken(r)) s.json(w, 200, user) }, ) s.mux.Path("/rest/projects").Methods("GET").HandlerFunc( func(w http.ResponseWriter, r *http.Request) { s.json(w, 200, s.config.Projects) }, ) s.mux.Path("/rest/status").Methods("GET").HandlerFunc( func(w http.ResponseWriter, r *http.Request) { s.json(w, 200, s.GetStatus("")) }, ) s.mux.Path("/rest/status/{project}").Methods("GET").HandlerFunc( func(w http.ResponseWriter, r *http.Request) { s.json(w, 200, s.GetStatus(mux.Vars(r)["project"])) }, ) s.mux.Path("/rest/deploy/{project}/{environment}").Methods("GET").HandlerFunc( func(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) status := 200 result := s.DoDeploy(ioutil.Discard, vars["project"], vars["environment"], true) if !result.Done { status = 500 } s.json(w, status, result) }, ) }
// sockjsHandlerWithRequest is a wrapper around the sockjs.Handler that // includes a *http.Request context. func sockjsHandlerWithRequest( prefix string, opts sockjs.Options, handleFunc func(sockjs.Session, *http.Request), ) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { sockjs.NewHandler(prefix, opts, func(session sockjs.Session) { handleFunc(session, r) }).ServeHTTP(w, r) }) }
func main() { defer db.Close() router := httprouter.New() n := negroni.Classic() n.UseHandler(router) router.GET("/", Home) router.GET("/page/:pg", Pagination) router.POST("/results/:pg", DisplaySearch) router.GET("/noresults", Noresults) router.GET("/login", Login) router.POST("/login", PostLogin) router.GET("/signup", Signup) router.POST("/signup", PostSignup) router.GET("/logout", Logout) router.GET("/authfail", Authfail) router.GET("/user", UserPage) router.GET("/item/:id", Itemid) router.POST("/deletefromcart", DeleteFromCart) router.GET("/addtocart", AddToCart) router.GET("/cart", CartPage) router.GET("/buy", BuyPage) router.POST("/checkout", Checkout) router.GET("/public/css/:cssfile", fileLoadHandler) handler := sockjs.NewHandler("/", sockjs.DefaultOptions, echoHandler) router.Handler("GET", "/chat", handler) n.Run(":2500") }
// WSHandler a middleware for `gohttp`. func WSHandler(prefix string) func(h http.Handler) http.Handler { return func(h http.Handler) http.Handler { if prefix == "" { prefix = PREFIX } ws := sockjs.NewHandler(prefix, sockjs.DefaultOptions, echoHandler) return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { if strings.HasPrefix(r.URL.Path, prefix) { ws.ServeHTTP(w, r) return } h.ServeHTTP(w, r) }) } }
func main() { filename := flag.String("config", "config.json", "Path to configuration file") flag.Parse() defer glog.Flush() var application = &system.Application{} application.Init(filename) application.LoadTemplates() application.ConnectToDatabase() // Setup static files static := web.New() static.Get("/assets/*", http.StripPrefix("/assets/", http.FileServer(http.Dir(application.Configuration.PublicPath)))) http.Handle("/assets/", static) // That's probably a terrible idea controllers.Template = application.Template controllers.MediaContent = application.Configuration.PublicPath + "/uploads/" http.Handle("/chat/", sockjs.NewHandler("/chat", sockjs.DefaultOptions, controllers.Chat)) // Apply middleware goji.Use(application.ApplyTemplates) goji.Use(application.ApplySessions) goji.Use(application.ApplyDatabase) goji.Use(application.ApplyAuth) controller := &controllers.MainController{} goji.Get("/", application.Route(controller, "Index")) goji.Get("/terms", application.Route(controller, "Terms")) goji.Get("/privacy", application.Route(controller, "Privacy")) graceful.PostHook(func() { application.Close() }) goji.Serve() }
func Setup(r pork.Router, ctx *context.Context) error { var h hub h.start() hand := sockjs.NewHandler("/api/sock", sockjs.DefaultOptions, func(s sockjs.Session) { sess, err := authenticate(s, ctx) if err != nil { accessDenied(s) return } user, err := sess.User(ctx) if err != nil { accessDenied(s) return } h.enter(s, user) defer h.leave(s, user) for { msg, err := s.Recv() if err != nil { log.Printf("recv: %s", err) return } if err := h.dispatch(s, user, msg); err != nil { log.Printf("disp: %s", err) return } } }) r.RespondWith("/api/sock/", pork.ResponderFor(hand)) return nil }
// New creates, initialize and then returns a new Kite instance. Version must // be in 3-digit semantic form. Name is important that it's also used to be // searched by others. func New(name, version string) *Kite { if name == "" { panic("kite: name cannot be empty") } if digits := strings.Split(version, "."); len(digits) != 3 { panic("kite: version must be 3-digits semantic version") } kiteID, err := uuid.NewV4() if err != nil { panic(fmt.Sprintf("kite: cannot generate unique ID: %s", err.Error())) } l, setlevel := newLogger(name) kClient := &kontrolClient{ readyConnected: make(chan struct{}), readyRegistered: make(chan struct{}), registerChan: make(chan *url.URL, 1), } k := &Kite{ Config: config.New(), Log: l, SetLogLevel: setlevel, Authenticators: make(map[string]func(*Request) error), trustedKontrolKeys: make(map[string]string), handlers: make(map[string]*Method), preHandlers: make([]Handler, 0), postHandlers: make([]Handler, 0), kontrol: kClient, name: name, version: version, Id: kiteID.String(), readyC: make(chan bool), closeC: make(chan bool), muxer: mux.NewRouter(), } // We change the heartbeat interval from 25 seconds to 10 seconds. This is // better for environments such as AWS ELB. sockjsOpts := sockjs.DefaultOptions sockjsOpts.HeartbeatDelay = 10 * time.Second // All sockjs communication is done through this endpoint.. k.muxer.PathPrefix("/kite").Handler(sockjs.NewHandler("/kite", sockjsOpts, k.sockjsHandler)) // Add useful debug logs k.OnConnect(func(c *Client) { k.Log.Debug("New session: %s", c.session.ID()) }) k.OnFirstRequest(func(c *Client) { k.Log.Debug("Session %q is identified as %q", c.session.ID(), c.Kite) }) k.OnDisconnect(func(c *Client) { k.Log.Debug("Kite has disconnected: %q", c.Kite) }) // Every kite should be able to authenticate the user from token. // Tokens are granted by Kontrol Kite. k.Authenticators["token"] = k.AuthenticateFromToken // A kite accepts requests with the same username. k.Authenticators["kiteKey"] = k.AuthenticateFromKiteKey // Register default methods and handlers. k.addDefaultHandlers() return k }
func main() { http.Handle("/echo/", sockjs.NewHandler("/echo", sockjs.DefaultOptions, echoHandler)) http.Handle("/", http.FileServer(http.Dir("web/"))) log.Println("Server started on port: 8080") log.Fatal(http.ListenAndServe(":8080", nil)) }
func newSockjsHandler(prefix string, options sockjs.Options, fn func(sockjs.Session)) *testHandler { return &testHandler{prefix, sockjs.NewHandler(prefix, options, fn)} }
// PrepareMux sets up the API func PrepareMux(flags *env.Flags) *web.Mux { // Set up a new logger log := logrus.New() // Set the formatter depending on the passed flag's value if flags.LogFormatterType == "text" { log.Formatter = &logrus.TextFormatter{ ForceColors: flags.ForceColors, } } else if flags.LogFormatterType == "json" { log.Formatter = &logrus.JSONFormatter{} } // Install Logrus hooks if flags.SlackURL != "" { var level []logrus.Level switch flags.SlackLevels { case "debug": level = slackrus.LevelThreshold(logrus.DebugLevel) case "error": level = slackrus.LevelThreshold(logrus.ErrorLevel) case "fatal": level = slackrus.LevelThreshold(logrus.FatalLevel) case "info": level = slackrus.LevelThreshold(logrus.InfoLevel) case "panic": level = slackrus.LevelThreshold(logrus.PanicLevel) case "warn": level = slackrus.LevelThreshold(logrus.WarnLevel) } log.Hooks.Add(&slackrus.SlackrusHook{ HookURL: flags.SlackURL, AcceptedLevels: level, Channel: flags.SlackChannel, IconEmoji: flags.SlackIcon, Username: flags.SlackUsername, }) } // Connect to raven var rc *raven.Client if flags.RavenDSN != "" { h, err := os.Hostname() if err != nil { log.Fatal(err) } rc, err = raven.NewClient(flags.RavenDSN, map[string]string{ "hostname": h, }) if err != nil { log.Fatal(err) } } env.Raven = rc // Pass it to the environment package env.Log = log // Load the bloom filter bf := bloom.NewWithEstimates(flags.BloomCount, 0.001) bff, err := os.Open(flags.BloomFilter) if err != nil { log.WithFields(logrus.Fields{ "error": err.Error(), }).Fatal("Unable to open the bloom filter file") } defer bff.Close() if _, err := bf.ReadFrom(bff); err != nil { log.WithFields(logrus.Fields{ "error": err.Error(), }).Fatal("Unable to read from the bloom filter file") } env.PasswordBF = bf // Initialize the cache redis, err := cache.NewRedisCache(&cache.RedisCacheOpts{ Address: flags.RedisAddress, Database: flags.RedisDatabase, Password: flags.RedisPassword, }) if err != nil { log.WithFields(logrus.Fields{ "error": err, }).Fatal("Unable to connect to the redis server") } env.Cache = redis // Set up the database rethinkOpts := gorethink.ConnectOpts{ Address: flags.RethinkDBAddress, AuthKey: flags.RethinkDBKey, MaxIdle: 10, Timeout: time.Second * 10, } err = db.Setup(rethinkOpts) if err != nil { log.WithFields(logrus.Fields{ "error": err, }).Fatal("Unable to set up the database") } // Initialize the actual connection rethinkOpts.Database = flags.RethinkDBDatabase rethinkSession, err := gorethink.Connect(rethinkOpts) if err != nil { log.WithFields(logrus.Fields{ "error": err, }).Fatal("Unable to connect to the database") } // Put the RethinkDB session into the environment package env.Rethink = rethinkSession // Initialize factors env.Factors = make(map[string]factor.Factor) if flags.YubiCloudID != "" { yubicloud, err := factor.NewYubiCloud(flags.YubiCloudID, flags.YubiCloudKey) if err != nil { env.Log.WithFields(logrus.Fields{ "error": err, }).Fatal("Unable to initiate YubiCloud") } env.Factors[yubicloud.Type()] = yubicloud } authenticator := factor.NewAuthenticator(6) env.Factors[authenticator.Type()] = authenticator // Initialize the tables env.Tokens = &db.TokensTable{ RethinkCRUD: db.NewCRUDTable( rethinkSession, rethinkOpts.Database, "tokens", ), Cache: redis, } env.Accounts = &db.AccountsTable{ RethinkCRUD: db.NewCRUDTable( rethinkSession, rethinkOpts.Database, "accounts", ), Tokens: env.Tokens, } env.Addresses = &db.AddressesTable{ RethinkCRUD: db.NewCRUDTable( rethinkSession, rethinkOpts.Database, "addresses", ), } env.Keys = &db.KeysTable{ RethinkCRUD: db.NewCRUDTable( rethinkSession, rethinkOpts.Database, "keys", ), } env.Contacts = &db.ContactsTable{ RethinkCRUD: db.NewCRUDTable( rethinkSession, rethinkOpts.Database, "contacts", ), } env.Reservations = &db.ReservationsTable{ RethinkCRUD: db.NewCRUDTable( rethinkSession, rethinkOpts.Database, "reservations", ), } env.Emails = &db.EmailsTable{ RethinkCRUD: db.NewCRUDTable( rethinkSession, rethinkOpts.Database, "emails", ), } env.Threads = &db.ThreadsTable{ RethinkCRUD: db.NewCRUDTable( rethinkSession, rethinkOpts.Database, "threads", ), } env.Labels = &db.LabelsTable{ RethinkCRUD: db.NewCRUDTable( rethinkSession, rethinkOpts.Database, "labels", ), Emails: env.Emails, //Cache: redis, } env.Files = &db.FilesTable{ Emails: env.Emails, RethinkCRUD: db.NewCRUDTable( rethinkSession, rethinkOpts.Database, "files", ), } // Create a producer producer, err := nsq.NewProducer(flags.NSQdAddress, nsq.NewConfig()) if err != nil { env.Log.WithFields(logrus.Fields{ "error": err.Error(), }).Fatal("Unable to create a new nsq producer") } /*defer func(producer *nsq.Producer) { producer.Stop() }(producer)*/ env.Producer = producer // Get the hostname hostname, err := os.Hostname() if err != nil { env.Log.WithFields(logrus.Fields{ "error": err.Error(), }).Fatal("Unable to get the hostname") } // Create a delivery consumer deliveryConsumer, err := nsq.NewConsumer("email_delivery", hostname, nsq.NewConfig()) if err != nil { env.Log.WithFields(logrus.Fields{ "error": err.Error(), "topic": "email_delivery", }).Fatal("Unable to create a new nsq consumer") } //defer deliveryConsumer.Stop() deliveryConsumer.AddConcurrentHandlers(nsq.HandlerFunc(func(m *nsq.Message) error { // Raven recoverer defer func() { rec := recover() if rec == nil { return } msg := &raven.Message{ Message: string(m.Body), Params: []interface{}{"delivery"}, } var packet *raven.Packet switch rval := recover().(type) { case error: packet = raven.NewPacket(rval.Error(), msg, raven.NewException(rval, raven.NewStacktrace(2, 3, nil))) default: str := fmt.Sprintf("%+v", rval) packet = raven.NewPacket(str, msg, raven.NewException(errors.New(str), raven.NewStacktrace(2, 3, nil))) } rc.Capture(packet, nil) }() var msg *struct { ID string `json:"id"` Owner string `json:"owner"` } if err := json.Unmarshal(m.Body, &msg); err != nil { return err } // Check if we are handling owner's session if _, ok := sessions[msg.Owner]; !ok { return nil } if len(sessions[msg.Owner]) == 0 { return nil } // Resolve the email email, err := env.Emails.GetEmail(msg.ID) if err != nil { env.Log.WithFields(logrus.Fields{ "error": err.Error(), "id": msg.ID, }).Error("Unable to resolve an email from queue") return nil } // Resolve the thread thread, err := env.Threads.GetThread(email.Thread) if err != nil { env.Log.WithFields(logrus.Fields{ "error": err.Error(), "id": msg.ID, "thread": email.Thread, }).Error("Unable to resolve a thread from queue") return nil } // Send notifications to subscribers for _, session := range sessions[msg.Owner] { result, _ := json.Marshal(map[string]interface{}{ "type": "delivery", "id": msg.ID, "name": email.Name, "thread": email.Thread, "labels": thread.Labels, }) err = session.Send(string(result)) if err != nil { env.Log.WithFields(logrus.Fields{ "id": session.ID(), "error": err.Error(), }).Warn("Error while writing to a WebSocket") } } return nil }), 10) if err := deliveryConsumer.ConnectToNSQLookupd(flags.LookupdAddress); err != nil { env.Log.WithFields(logrus.Fields{ "error": err.Error(), }).Fatal("Unable to connect to nsqlookupd") } // Create a receipt consumer receiptConsumer, err := nsq.NewConsumer("email_receipt", hostname, nsq.NewConfig()) if err != nil { env.Log.WithFields(logrus.Fields{ "error": err.Error(), "topic": "email_receipt", }).Fatal("Unable to create a new nsq consumer") } //defer receiptConsumer.Stop() receiptConsumer.AddConcurrentHandlers(nsq.HandlerFunc(func(m *nsq.Message) error { // Raven recoverer defer func() { rec := recover() if rec == nil { return } msg := &raven.Message{ Message: string(m.Body), Params: []interface{}{"receipt"}, } var packet *raven.Packet switch rval := recover().(type) { case error: packet = raven.NewPacket(rval.Error(), msg, raven.NewException(rval, raven.NewStacktrace(2, 3, nil))) default: str := fmt.Sprintf("%+v", rval) packet = raven.NewPacket(str, msg, raven.NewException(errors.New(str), raven.NewStacktrace(2, 3, nil))) } rc.Capture(packet, nil) }() var msg *struct { ID string `json:"id"` Owner string `json:"owner"` } if err := json.Unmarshal(m.Body, &msg); err != nil { return err } // Check if we are handling owner's session if _, ok := sessions[msg.Owner]; !ok { return nil } if len(sessions[msg.Owner]) == 0 { return nil } // Resolve the email email, err := env.Emails.GetEmail(msg.ID) if err != nil { env.Log.WithFields(logrus.Fields{ "error": err.Error(), "id": msg.ID, }).Error("Unable to resolve an email from queue") return nil } // Resolve the thread thread, err := env.Threads.GetThread(email.Thread) if err != nil { env.Log.WithFields(logrus.Fields{ "error": err.Error(), "id": msg.ID, "thread": email.Thread, }).Error("Unable to resolve a thread from queue") return nil } // Send notifications to subscribers for _, session := range sessions[msg.Owner] { result, _ := json.Marshal(map[string]interface{}{ "type": "receipt", "id": msg.ID, "name": email.Name, "thread": email.Thread, "labels": thread.Labels, }) err = session.Send(string(result)) if err != nil { env.Log.WithFields(logrus.Fields{ "id": session.ID(), "error": err.Error(), }).Warn("Error while writing to a WebSocket") } } return nil }), 10) if err := receiptConsumer.ConnectToNSQLookupd(flags.LookupdAddress); err != nil { env.Log.WithFields(logrus.Fields{ "error": err.Error(), }).Fatal("Unable to connect to nsqlookupd") } // Create a new goji mux mux := web.New() // Include the most basic middlewares: // - RequestID assigns an unique ID for each request in order to identify errors. // - Glogrus logs each request // - Recoverer prevents panics from crashing the API // - AutomaticOptions automatically responds to OPTIONS requests mux.Use(func(c *web.C, h http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { // sockjs doesn't want to work with our code, as the author doesn't understand http.Headers if strings.HasPrefix(r.RequestURI, "/ws") { h.ServeHTTP(w, r) return } // because why not w.Header().Set("Access-Control-Allow-Credentials", "true") allowedHeaders := []string{ "Origin", "Content-Type", "Authorization", "X-Requested-With", } reqHeaders := strings.Split(r.Header.Get("Access-Control-Request-Headers"), ",") allowedHeaders = append(allowedHeaders, reqHeaders...) resultHeaders := []string{} seenHeaders := map[string]struct{}{} for _, val := range allowedHeaders { if _, ok := seenHeaders[val]; !ok && val != "" { resultHeaders = append(resultHeaders, val) seenHeaders[val] = struct{}{} } } w.Header().Set("Access-Control-Allow-Headers", strings.Join(resultHeaders, ",")) /* if c.Env != nil { if v, ok := c.Env[web.ValidMethodsKey]; ok { if methods, ok := v.([]string); ok { methodsString := strings.Join(methods, ",") w.Header().Set("Allow", methodsString) w.Header().Set("Access-Control-Allow-Methods", methodsString) } } } */ // yolo w.Header().Set("Access-Control-Allow-Methods", "GET,POST,PUT,DELETE") w.Header().Set("Access-Control-Allow-Origin", "*") if r.Method != "OPTIONS" { h.ServeHTTP(w, r) } }) }) mux.Use(middleware.RequestID) //mux.Use(glogrus.NewGlogrus(log, "api")) mux.Use(recoverer) mux.Use(middleware.AutomaticOptions) // Set up an auth'd mux auth := web.New() auth.Use(routes.AuthMiddleware) // Index route mux.Get("/", routes.Hello) // Accounts auth.Get("/accounts", routes.AccountsList) mux.Post("/accounts", routes.AccountsCreate) auth.Get("/accounts/:id", routes.AccountsGet) auth.Put("/accounts/:id", routes.AccountsUpdate) auth.Delete("/accounts/:id", routes.AccountsDelete) auth.Post("/accounts/:id/wipe-data", routes.AccountsWipeData) auth.Post("/accounts/:id/start-onboarding", routes.AccountsStartOnboarding) // Addresses auth.Get("/addresses", routes.AddressesList) // Avatars mux.Get(regexp.MustCompile(`/avatars/(?P<hash>[\S\s]*?)\.(?P<ext>svg|png)(?:[\S\s]*?)$`), routes.Avatars) //mux.Get("/avatars/:hash.:ext", routes.Avatars) // Files auth.Get("/files", routes.FilesList) auth.Post("/files", routes.FilesCreate) auth.Get("/files/:id", routes.FilesGet) auth.Put("/files/:id", routes.FilesUpdate) auth.Delete("/files/:id", routes.FilesDelete) // Tokens auth.Get("/tokens", routes.TokensGet) auth.Get("/tokens/:id", routes.TokensGet) mux.Post("/tokens", routes.TokensCreate) auth.Delete("/tokens", routes.TokensDelete) auth.Delete("/tokens/:id", routes.TokensDelete) // Threads auth.Get("/threads", routes.ThreadsList) auth.Get("/threads/:id", routes.ThreadsGet) auth.Put("/threads/:id", routes.ThreadsUpdate) auth.Delete("/threads/:id", routes.ThreadsDelete) // Emails auth.Get("/emails", routes.EmailsList) auth.Post("/emails", routes.EmailsCreate) auth.Get("/emails/:id", routes.EmailsGet) auth.Delete("/emails/:id", routes.EmailsDelete) // Labels auth.Get("/labels", routes.LabelsList) auth.Post("/labels", routes.LabelsCreate) auth.Get("/labels/:id", routes.LabelsGet) auth.Put("/labels/:id", routes.LabelsUpdate) auth.Delete("/labels/:id", routes.LabelsDelete) // Contacts auth.Get("/contacts", routes.ContactsList) auth.Post("/contacts", routes.ContactsCreate) auth.Get("/contacts/:id", routes.ContactsGet) auth.Put("/contacts/:id", routes.ContactsUpdate) auth.Delete("/contacts/:id", routes.ContactsDelete) // Keys mux.Get("/keys", routes.KeysList) auth.Post("/keys", routes.KeysCreate) mux.Get("/keys/:id", routes.KeysGet) auth.Post("/keys/:id/vote", routes.KeysVote) // Headers proxy mux.Get("/headers", func(w http.ResponseWriter, r *http.Request) { utils.JSONResponse(w, 200, r.Header) }) mux.Handle("/ws/*", sockjs.NewHandler("/ws", sockjs.DefaultOptions, func(session sockjs.Session) { var subscribed string // A new goroutine seems to be spawned for each new session for { // Read a message from the input msg, err := session.Recv() if err != nil { if err != sockjs.ErrSessionNotOpen { env.Log.WithFields(logrus.Fields{ "id": session.ID(), "error": err.Error(), }).Warn("Error while reading from a WebSocket") } break } // Decode the message var input struct { Type string `json:"type"` Token string `json:"token"` ID string `json:"id"` Method string `json:"method"` Path string `json:"path"` Body string `json:"body"` Headers map[string]string `json:"headers"` } err = json.Unmarshal([]byte(msg), &input) if err != nil { // Return an error response resp, _ := json.Marshal(map[string]interface{}{ "type": "error", "error": err, }) err := session.Send(string(resp)) if err != nil { env.Log.WithFields(logrus.Fields{ "id": session.ID(), "error": err.Error(), }).Warn("Error while writing to a WebSocket") break } continue } // Check message's type if input.Type == "subscribe" { // Listen to user's events // Check if token is empty if input.Token == "" { // Return an error response resp, _ := json.Marshal(map[string]interface{}{ "type": "error", "error": "Invalid token", }) err := session.Send(string(resp)) if err != nil { env.Log.WithFields(logrus.Fields{ "id": session.ID(), "error": err.Error(), }).Warn("Error while writing to a WebSocket") break } continue } // Check the token in database token, err := env.Tokens.GetToken(input.Token) if err != nil { // Return an error response resp, _ := json.Marshal(map[string]interface{}{ "type": "error", "error": "Invalid token", }) err := session.Send(string(resp)) if err != nil { env.Log.WithFields(logrus.Fields{ "id": session.ID(), "error": err.Error(), }).Warn("Error while writing to a WebSocket") break } continue } // Do the actual subscription subscribed = token.Owner sessionsLock.Lock() // Sessions map already contains this owner if _, ok := sessions[token.Owner]; ok { sessions[token.Owner] = append(sessions[token.Owner], session) } else { // We have to allocate a new slice sessions[token.Owner] = []sockjs.Session{session} } // Unlock the map write sessionsLock.Unlock() // Return a response resp, _ := json.Marshal(map[string]interface{}{ "type": "subscribed", }) err = session.Send(string(resp)) if err != nil { env.Log.WithFields(logrus.Fields{ "id": session.ID(), "error": err.Error(), }).Warn("Error while writing to a WebSocket") break } } else if input.Type == "unsubscribe" { if subscribed == "" { resp, _ := json.Marshal(map[string]interface{}{ "type": "error", "error": "Not subscribed", }) err := session.Send(string(resp)) if err != nil { env.Log.WithFields(logrus.Fields{ "id": session.ID(), "error": err.Error(), }).Warn("Error while writing to a WebSocket") break } } sessionsLock.Lock() if _, ok := sessions[subscribed]; !ok { // Return a response resp, _ := json.Marshal(map[string]interface{}{ "type": "unsubscribed", }) err := session.Send(string(resp)) if err != nil { env.Log.WithFields(logrus.Fields{ "id": session.ID(), "error": err.Error(), }).Warn("Error while writing to a WebSocket") sessionsLock.Unlock() subscribed = "" break } sessionsLock.Unlock() subscribed = "" continue } if len(sessions[subscribed]) == 1 { delete(sessions, subscribed) // Return a response resp, _ := json.Marshal(map[string]interface{}{ "type": "unsubscribed", }) err := session.Send(string(resp)) if err != nil { env.Log.WithFields(logrus.Fields{ "id": session.ID(), "error": err.Error(), }).Warn("Error while writing to a WebSocket") sessionsLock.Unlock() subscribed = "" break } sessionsLock.Unlock() subscribed = "" continue } // Find the session index := -1 for i, session2 := range sessions[subscribed] { if session == session2 { index = i break } } // We didn't find anything if index == -1 { // Return a response resp, _ := json.Marshal(map[string]interface{}{ "type": "unsubscribed", }) err := session.Send(string(resp)) if err != nil { env.Log.WithFields(logrus.Fields{ "id": session.ID(), "error": err.Error(), }).Warn("Error while writing to a WebSocket") sessionsLock.Unlock() subscribed = "" break } sessionsLock.Unlock() subscribed = "" continue } // We found it, so we are supposed to slice it sessions[subscribed][index] = sessions[subscribed][len(sessions[subscribed])-1] sessions[subscribed][len(sessions[subscribed])-1] = nil sessions[subscribed] = sessions[subscribed][:len(sessions[subscribed])-1] // Return a response resp, _ := json.Marshal(map[string]interface{}{ "type": "unsubscribed", }) err := session.Send(string(resp)) if err != nil { env.Log.WithFields(logrus.Fields{ "id": session.ID(), "error": err.Error(), }).Warn("Error while writing to a WebSocket") sessionsLock.Unlock() subscribed = "" break } sessionsLock.Unlock() subscribed = "" } else if input.Type == "request" { // Perform the request w := httptest.NewRecorder() r, err := http.NewRequest(strings.ToUpper(input.Method), "http://api.lavaboom.io"+input.Path, strings.NewReader(input.Body)) if err != nil { env.Log.WithFields(logrus.Fields{ "id": session.ID(), "error": err.Error(), "path": input.Path, }).Warn("SockJS request error") // Return an error response resp, _ := json.Marshal(map[string]interface{}{ "error": err.Error(), }) err := session.Send(string(resp)) if err != nil { env.Log.WithFields(logrus.Fields{ "id": session.ID(), "error": err.Error(), }).Warn("Error while writing to a WebSocket") break } continue } r.Body = nopCloser{strings.NewReader(input.Body)} r.RequestURI = input.Path for key, value := range input.Headers { r.Header.Set(key, value) } mux.ServeHTTP(w, r) // Return the final response result, _ := json.Marshal(map[string]interface{}{ "type": "response", "id": input.ID, "status": w.Code, "headers": w.HeaderMap, "body": w.Body.String(), }) err = session.Send(string(result)) if err != nil { env.Log.WithFields(logrus.Fields{ "id": session.ID(), "error": err.Error(), }).Warn("Error while writing to a WebSocket") break } } } // We have to clear the subscription here too. TODO: make the code shorter if subscribed == "" { return } sessionsLock.Lock() if _, ok := sessions[subscribed]; !ok { sessionsLock.Unlock() return } if len(sessions[subscribed]) == 1 { delete(sessions, subscribed) sessionsLock.Unlock() return } // Find the session index := -1 for i, session2 := range sessions[subscribed] { if session == session2 { index = i break } } // We didn't find anything if index == -1 { sessionsLock.Unlock() return } // We found it, so we are supposed to slice it sessions[subscribed][index] = sessions[subscribed][len(sessions[subscribed])-1] sessions[subscribed][len(sessions[subscribed])-1] = nil sessions[subscribed] = sessions[subscribed][:len(sessions[subscribed])-1] // Unlock the mutex sessionsLock.Unlock() })) // Merge the muxes mux.Handle("/*", auth) // Compile the routes mux.Compile() return mux }
func serve() { log.Println("serving...") memory := make(map[string]InMemoryFile) var sessions []sockjs.Session http.Handle("/_sockjs/", sockjs.NewHandler("/_sockjs", sockjs.DefaultOptions, func(session sockjs.Session) { log.Println("SOCKJS : getting session", session) sessions = append(sessions, session) // for { // if msg, err := session.Recv(); err == nil { // session.Send(msg) // continue // } // break // } })) http.Handle("/", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { log.Printf("handling response : %q", html.EscapeString(r.URL.Path)) //fmt.Fprintf(w, "Hello : %q", html.EscapeString(r.URL.Path)) path := r.URL.Path if r.Method == "PUT" { log.Println("handling PUT") r.ParseMultipartForm(32 << 20) file, _, fileFormErr := r.FormFile("file") if fileFormErr != nil { log.Println("FileFormErr", fileFormErr) return } defer file.Close() fileBytes, readErr := ioutil.ReadAll(file) if readErr != nil { log.Println("read error", readErr) } log.Println("FileBytes", string(fileBytes)) memory[path] = InMemoryFile{Bytes: fileBytes, Time: time.Now()} for _, session := range sessions { session.Send("write:" + path) } } else if r.Method == "GET" { log.Println("Getting...") value, ok := memory[path] if ok { if !checkLastModified(w, r, value.Time) { //TODO use the time w.Write(value.Bytes) } } else { w.WriteHeader(404) fmt.Fprint(w, "not found : "+r.URL.String()) } } else if r.Method == "DELETE" { log.Println("Deleting...") delete(memory, path) for _, session := range sessions { session.Send("delete:" + path) } } else { log.Println("NOT HANDLED") } })) go listen() }
func NewHandler(prefix string) http.Handler { return sockjs.NewHandler(prefix, sockjs.DefaultOptions, quoridorHandler) }
func NewHandler(cmd env.Commander) http.Handler { ws := &Ws{cmd} return sockjs.NewHandler("/ws", sockjs.DefaultOptions, ws.Handler) }
func main() { rooms = make(map[int]*ng.Room) clientToRooms = make(map[sockjs.Session]*ng.Room) handler := sockjs.NewHandler("/sockjs", sockjs.DefaultOptions, sockjsHandler) log.Fatal(http.ListenAndServe("127.0.0.1:"+*flag.String("port", "8081", "Port"), handler)) }
} func receiveMessage(session sockjs.Session) { reader, _ := pub.SubChannel(nil) for { select { case msg, ok := <-reader: if !ok { log.Println("channel closed") return } msg = msg.(*socketMessage) if body, err := json.Marshal(msg); err == nil { log.Println("message:", string(body)) if err = session.Send(string(body)); err != nil { log.Println(err) return } } } } } var messageHandler = sockjs.NewHandler( "/api/messages", sockjs.DefaultOptions, func(session sockjs.Session) { go func() { receiveMessage(session) }() })