Giter VIP home page Giter VIP logo

korolev's People

Contributors

artembakhanov avatar clayrat avatar esardes avatar fly-style avatar fomkin avatar greenhost87 avatar gregor-i avatar landlockedsurfer avatar marc-ducret avatar morozov11 avatar nartamonov avatar olivierdeckers avatar optician avatar road21 avatar solverit avatar strobe avatar tvaroh avatar valentiay avatar vitaliis avatar vovapolu avatar zhen-hao avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

korolev's Issues

File upload support

Proposal

FormData allows to send HTML forms asynchronously. Idea is to send forms via HTTP[S] and notify about progress via WebSocket.

Algorithm

  1. User presses "Submit" button.
  2. Event received by korolev-server
  3. Server initiates FromData uploading using XMLHttpRequest.send
  4. Client invoke progress callback for every progress event

API

val myForm = elementId

'form(

  myForm,

  eventWithAccess('submit) { access => 
    access
      .downloadFormData(myForm)
      .onProgress { (loaded, total) =>
        // transition …
      }
      .start
      .map { formData =>
        val picture = data.file("picture") // Array[Byte]
        val title = data.text("title") // String
        // transition ...
      }
  },
        
  'input('name = "title", 'type /= "text"),
  'input('name = "picture", 'type /= "file"),
  'input('type /= "button", "Submit")
)

Tasks

  1. multipart/form-data codec
  2. Allow Korolev to receive FormData
  3. Progress events
  4. Example

Example did not run as according to docs

Downloaded https://repo1.maven.org/maven2/com/lihaoyi/utest_2.11/0.4.4/utest_2.11-0.4.4.jar
[info] Compiling 1 Scala source to C:\home\projects\git\korolev\async.jvm\target\scala-2.11\classes...
[info] Compiling 2 Scala sources to C:\home\projects\git\korolev\vdom.jvm\target\scala-2.11\classes...
[info] Compiling 5 Scala sources to C:\home\projects\git\korolev\bridge.jvm\target\scala-2.11\classes...
[info] Compiling 8 Scala sources to C:\home\projects\git\korolev\korolev.jvm\target\scala-2.11\classes...
[info] Compiling 8 Scala sources to C:\home\projects\git\korolev\server\target\scala-2.11\classes...
[info] Compiling 6 Scala sources to C:\home\projects\git\korolev\server-blaze\target\scala-2.11\classes...
java.lang.RuntimeException: No main class detected.
at scala.sys.package$.error(package.scala:27)
[trace] Stack trace suppressed: run last simpleExample/compile:run for the full output.
[error] (simpleExample/compile:run) No main class detected.
[error] Total time: 28 s, completed Feb 18, 2017 10:53:34 AM

C:\home\projects\git\korolev>sbt simpleExample/run

Reconnect support

Looks like we need to have session management.

  1. State for every session should be stored in abstract KV storage (simple concurrent mutable map by default).
  2. When user enter the server first time server sets cookie with unique session key.
  3. When user enter next time state should be restored.

Make KorolevServer easy to implement on top of any HTTP/WS framework

Currently we bound on http4s. It should become a module named http4s with Task as IO monad. KorlevServerHttp4s should generate rout, not runnable.

val application = Korolev(TheState.empty)
  .bindHttp(port, host)
  .render(renderPartialFunction)
  .stateStorage(stateStorageInstance)

Use page local session id instead cookie.

  1. Every browser should have deviceId. If it absent we have to set it using cookie.
  2. Add deviceId to State resolver. It is state generator for new sessions.
  3. Initial state should be finally dropped.

Remove KorolevAccess.

Now access objects make render functions impure. This disallow to enable memorization for render functions.

Write documentation

  • 1. Introduction
  • 1.1. Principles
  • 2. Understanding Korolev
  • 2.1. Device and Session
  • 2.2. State
  • 2.3. Render
  • 2.4. Transitions
  • 2.5. Events
  • 2.6. EventResult
  • 2.7. FormData
  • 2.8. Delays
  • 2.9. External Binding
  • 2.10. Routing
  • 3.3. Web Components
  • 4. Integrations
  • 4.1. JCache

Metrics support

Allow to plug metric trackers. What should be tracked:

  1. State loading (for new sessions, existing sessions)
  2. Static pages rendering
  3. Diffs
  4. Routing

Timers: way to schedule transitions

It may be useful when we want to play some basic animation or hide something after timeout.

Global timer (session context)

KorolevServer[Boolean](
  ...
  timers = {
    case true => 
      delay(2 seconds) {
         case _ => false
      }
  }
)

Inside view

render = {
  case state =>
    'div(
      h1("Title"),
      if (!state) <> 
      else 'div(
        "Something we want to hide",
        delay(2 seconds) {
          case _ => false
        }
      )
    )
}

Problems found by basic load test with artilery

We are using Artillery framework for load testing. I launched basic quick load test for routingExample artillery quick --duration 20 --rate 5 -n 5 http://localhost:8181 ,

I got that big stack trace (I recduced it a little) :

[ForkJoinPool-1-worker-1] ERROR org.http4s.blaze.pipeline.Stage - Error during 'handleRequest' of HttpServerStage
scala.MatchError: [Ljava.lang.String;@623a6f (of class [Ljava.lang.String;)
[ForkJoinPool-1-worker-1] INFO org.http4s.blaze.pipeline.Stage - Shutting down HttpPipeline at Tue Jan 31 10:48:06 EET 2017
[ForkJoinPool-1-worker-1] ERROR org.http4s.blaze.pipeline.Stage - NIO2 channel closed with an unexpected error
scala.MatchError: [Ljava.lang.String;@623a6f (of class [Ljava.lang.String;)

It seems like there are some problems in cookies handling.

Exception throws sometimes

routingExample[ERROR] bridge.JSAccess$JSSideException: [object Object].ListenEvent(clic
routingExample[ERROR] 	at bridge.JSAccess.resolvePromise(JSAccess.scala:141)
routingExample[ERROR] 	at korolev.server.JsonQueuedJsAccess.receive(JsonQueuedJsAccess.scala:95)
routingExample[ERROR] 	at korolev.server.package$$anonfun$1.$anonfun$applyOrElse$9(package.scala:114)
routingExample[ERROR] 	at korolev.server.package$$anonfun$1.$anonfun$applyOrElse$9$adapted(package.scala:114)
routingExample[ERROR] 	at korolev.blazeServer.package$$anon$1.onMessage(package.scala:81)
routingExample[ERROR] 	at korolev.blazeServer.WebSocketStage.$anonfun$_wsLoop$1(WebSocketStage.scala:28)
routingExample[ERROR] 	at korolev.blazeServer.WebSocketStage.$anonfun$_wsLoop$1$adapted(WebSocketStage.scala:24)
routingExample[ERROR] 	at scala.concurrent.impl.CallbackRunnable.run(Promise.scala:60)
routingExample[ERROR] 	at org.http4s.blaze.util.Execution$$anon$1.execute(Executor.scala:27)
routingExample[ERROR] 	at scala.concurrent.impl.CallbackRunnable.executeWithValue(Promise.scala:68)
routingExample[ERROR] 	at scala.concurrent.impl.Promise$DefaultPromise.$anonfun$tryComplete$1(Promise.scala:284)
routingExample[ERROR] 	at scala.concurrent.impl.Promise$DefaultPromise.$anonfun$tryComplete$1$adapted(Promise.scala:284)
routingExample[ERROR] 	at scala.concurrent.impl.Promise$DefaultPromise.tryComplete(Promise.scala:284)
routingExample[ERROR] 	at scala.concurrent.Promise.trySuccess(Promise.scala:90)
routingExample[ERROR] 	at scala.concurrent.Promise.trySuccess$(Promise.scala:90)
routingExample[ERROR] 	at scala.concurrent.impl.Promise$DefaultPromise.trySuccess(Promise.scala:183)
routingExample[ERROR] 	at org.http4s.blaze.channel.nio2.ByteBufferHead$$anon$3.completed(ByteBufferHead.scala:100)
routingExample[ERROR] 	at org.http4s.blaze.channel.nio2.ByteBufferHead$$anon$3.completed(ByteBufferHead.scala:87)

Add/Remove hooks

Do some JavaScript when DOM element added/removed from from virtual DOM

EU Cookie Law support

Korolev requires cookie to work. EU Cookie Law requires warn user about that. It can be done by programmer (just add closable panel to top of page) or Korolev, before the deviceId will be set.

SSL support out of box

A lot of people say that unsecure Korolev pages don't works because corporative secure policy forbid WebSockets (or proxy doesn't support them). We need to have SSL support.

Diff algorithm preforms poorly on prepend

The diff algorithm works fine when appending:

val a = 'div (
  'h2 /= "", 'h1 /= "", 'h2 /= "", 'h1 /= "", 'h2 /= "", 'h1 /= "", 'h2 /= "")

val b = 'div (
  'h2 /= "", 'h1 /= "", 'h2 /= "", 'h1 /= "", 'h2 /= "", 'h1 /= "", 'h2 /= "",
  'h1 /= "new")
  
VDom.changes(a, b) == List(SetAttr(0,"h1","new",false))

But seams to preform poorly when prepending:

val a = 'div (
  'h2 /= "", 'h1 /= "", 'h2 /= "", 'h1 /= "", 'h2 /= "", 'h1 /= "", 'h2 /= "")

val b = 'div (
  'h1 /= "new",
  'h2 /= "", 'h1 /= "", 'h2 /= "", 'h1 /= "", 'h2 /= "", 'h1 /= "", 'h2 /= "")

VDom.changes(a, b) == List(
  SetAttr(0,"h2","",false),
  RemoveAttr(0,"h2",""false),
  SetAttr(0,"h1","",false),
  RemoveAttr(0,"h1",""false),
  SetAttr(0,"h2","",false),
  RemoveAttr(0,"h2",""false),
  SetAttr(0,"h1","",false),
  RemoveAttr(0,"h1",""false),
  SetAttr(0,"h2","",false),
  RemoveAttr(0,"h2",""false),
  SetAttr(0,"h1","",false),
  RemoveAttr(0,"h1",""false),
  SetAttr(0,"h2","",false),
  RemoveAttr(0,"h2",""false),
  SetAttr(0,"h1","new",false)
)

FWIW the kivi implementation seams to hande these cases while remaining reasonably simple

Listen any event

No we able listen only mousedown, mouseup, click and submit. We need to be able to listen any event.

Inline styles

'div(
  'border @= "1px solid red"
  'backgroundColor @= "black",
  "Hello world"
)

Support static assets such as images, js, css

When a http request comes in it goes through korolev/server/package.scala:

def renderStatic(request: Request): F[Response] = {

If the file is a javascript static resource then it returns

<!DOCTYPE html><html ><head ><script > then the javascript code -

resulting in a error

Routing

What is Router?

case class Router[F[_]: Async, S](
  from: S => Path,
  to: (DeviceId, Path) => F[S]
)

Router should:

  1. Map State to the Path. For example we have state case class State(blogId: String @@ Blog, articleId: String @@ Article, text: String). So path is /blogs/${state.blogId}/articles/${state.articleId}.
  2. Map Path to the State. We should remember that state state generation can produce side effects like DB access.

Remove dependency on standard Futures

When people want to use Scalaz or Cats they are don't want to use Future from standard library. I think we have to write our own monad like type class. Good namings: Async, Deferred

Korolev initialization hangs

Connection opened.
batch,0,getAndSaveAs,@link:global,Korolev,@Korolev,1,registerCallback,^cb0
0,getAndSaveAs,@link:global,Korolev,@Korolev
0,true,@obj:@Korolev
1,registerCallback,^cb0
1,true,@obj:^cb0
batch,2,registerCallback,^cb1
2,registerCallback,^cb1
2,true,@obj:^cb1
batch,3,call,@link:@Korolev,SetRenderNum,0
3,call,@link:@Korolev,SetRenderNum,0
3,true,@unit
batch,4,call,@link:@Korolev,RegisterHistoryHandler,@link:^cb0
4,call,@link:@Korolev,RegisterHistoryHandler,@link:^cb0
4,true,@unit

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.