GithubHelp home page GithubHelp logo

netty-reactive-streams's Introduction

Play Framework - The High Velocity Web Framework

X (formerly Twitter) Follow Discord GitHub Discussions StackOverflow YouTube Twitch Status OpenCollective

Build Status Maven Repository size Scala Steward badge Mergify Status

The Play Framework combines productivity and performance making it easy to build scalable web applications with Java and Scala. Play is developer friendly with a "just hit refresh" workflow and built-in testing support. With Play, applications scale predictably due to a stateless and non-blocking architecture. By being RESTful by default, including assets compilers, JSON & WebSocket support, Play is a perfect fit for modern web & mobile applications.

Learn More

Sponsors & Backers

If you find Play useful for work, please consider asking your company to support this Open Source project by becoming a sponsor.
You can also individually sponsor the project by becoming a backer.

Thank you to our premium sponsors!

Thank you to all our backers!

License

Copyright (C) from 2022 The Play Framework Contributors https://github.com/playframework, 2011-2021 Lightbend Inc. https://www.lightbend.com

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this project except in compliance with the License. You may obtain a copy of the License at https://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.

netty-reactive-streams's People

Contributors

billyautrey avatar dagnir avatar dependabot[bot] avatar don-vip avatar dwijnand avatar georgepearman avatar gmethvin avatar ignasi35 avatar ihostage avatar jroper avatar jtjeferreira avatar marcospereira avatar mchv avatar mkurz avatar octonato avatar schmitch avatar spikhalskiy avatar sschuberth avatar sullis avatar theantimist avatar varunnvs92 avatar wsargent 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

netty-reactive-streams's Issues

Performance/Stability issues over HTTP

I’ve been banging my head against this for several days so I thought I’d reach out to the experts. We are using the reactive streams implementation to apply back pressure in sending/receiving HTTP requests. Originally we were using HandlerSubscriber and HandlerPublisher directly but were running into some concurrency issues where chunks were getting reordered somehow. I stumbled on the HTTP implementation (netty-reactive-streams-http) and decided to give that a try. When switching to that all the concurrency issues magically disappeared and I much prefer the simpler integration/API vs the low level handlers. When doing some perf testing though it seems to be orders of magnitude slower so I suspect I’m doing something wrong with my implementation. I suspect it’s got something to do with how I’m firing channel reads but I’m not exactly sure. One interesting thing is that if I close the channel after every request the performance is actually much better so perhaps I’m not leaving the channel/pipeline in a good state after the request. Any ideas on how to go about tracking this down? Apologies for being light on details, I’m struggling to understand all this myself. Any help you could provide would be greatly appreciated.

Where we add the streams handler, https://github.com/aws/aws-sdk-java-v2/blob/netty-reactive-streams-http/aws-http-nio-client-netty/src/main/java/software/amazon/awssdk/http/nio/netty/internal/ChannelPipelineInitializer.java#L65

Where we write the StreamedRequest, https://github.com/aws/aws-sdk-java-v2/blob/netty-reactive-streams-http/aws-http-nio-client-netty/src/main/java/software/amazon/awssdk/http/nio/netty/internal/RunnableRequest.java#L72

We have a custom StreamedHttpRequest that adapts a Publisher of ByteBuffer to a Publisher of HttpContent. https://github.com/aws/aws-sdk-java-v2/blob/netty-reactive-streams-http/aws-http-nio-client-netty/src/main/java/software/amazon/awssdk/http/nio/netty/internal/RunnableRequest.java#L163

Where we fire channelContext.read(), https://github.com/aws/aws-sdk-java-v2/blob/netty-reactive-streams-http/aws-http-nio-client-netty/src/main/java/software/amazon/awssdk/http/nio/netty/internal/ResponseHandler.java#L109

make ServerChannel as a Pubisher[Channel]

I was wandering how about make theServerChannelas Publisher[Channel],and then we setup the ChannelPipeline ,register it to eventloop.and then we may get can get the Publisher for the specified channel viadef StreamedChannelHandler.publisher:Future[Publisher]?
the publisher will only return and always return the same instance after the channel is active and the handler is added to the pipeline.

NPE in HandlerPublisher.handlerRemoved

From a project using nett-reactive-streams 2.0.4 (via https://github.com/AsyncHttpClient/async-http-client, whose StreamedResponsePublisher extends HandlerPublisher), I see the following exception:

2022-11-14 20:15:06,889 WARN  [] i.n.c.DefaultChannelPipeline        : An exceptionCaught() event was fired, and it reached at the tail of the pipeline. It usually means the last handler in the pipeline did not handle the exception.
io.netty.channel.ChannelPipelineException: org.asynchttpclient.netty.handler.StreamedResponsePublisher.handlerRemoved() has thrown an exception.
	at io.netty.channel.DefaultChannelPipeline.callHandlerRemoved0(DefaultChannelPipeline.java:640)
	at io.netty.channel.DefaultChannelPipeline.remove(DefaultChannelPipeline.java:477)
	at io.netty.channel.DefaultChannelPipeline.remove(DefaultChannelPipeline.java:417)
	at org.asynchttpclient.netty.handler.AsyncHttpClientHandler.channelRead(AsyncHttpClientHandler.java:94)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
	at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357)
	at io.netty.handler.codec.MessageToMessageDecoder.channelRead(MessageToMessageDecoder.java:103)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
	at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357)
	at io.netty.channel.CombinedChannelDuplexHandler$DelegatingChannelHandlerContext.fireChannelRead(CombinedChannelDuplexHandler.java:436)
	at io.netty.handler.codec.ByteToMessageDecoder.fireChannelRead(ByteToMessageDecoder.java:327)
	at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:299)
	at io.netty.channel.CombinedChannelDuplexHandler.channelRead(CombinedChannelDuplexHandler.java:251)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
	at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357)
	at io.netty.handler.ssl.SslHandler.unwrap(SslHandler.java:1372)
	at io.netty.handler.ssl.SslHandler.decodeJdkCompatible(SslHandler.java:1235)
	at io.netty.handler.ssl.SslHandler.decode(SslHandler.java:1284)
	at io.netty.handler.codec.ByteToMessageDecoder.decodeRemovalReentryProtection(ByteToMessageDecoder.java:510)
	at io.netty.handler.codec.ByteToMessageDecoder.callDecode(ByteToMessageDecoder.java:449)
	at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:279)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
	at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357)
	at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1410)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
	at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:919)
	at io.netty.channel.epoll.AbstractEpollStreamChannel$EpollStreamUnsafe.epollInReady(AbstractEpollStreamChannel.java:800)
	at io.netty.channel.epoll.EpollEventLoop.processReady(EpollEventLoop.java:480)
	at io.netty.channel.epoll.EpollEventLoop.run(EpollEventLoop.java:378)
	at io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:986)
	at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74)
	at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
	at java.base/java.lang.Thread.run(Thread.java:829)
Caused by: java.lang.NullPointerException: null

That doesn't include the original NPE's stacktrace unfortunately, but looking at the implementation of HandlerPublisher.complete(), the only line that can NPE is is the call to subscriber.onComplete(); (since buffer can never be null). The minimal solution is to add a null check around the call to subscriber.onComplete();.

I mistakenly commented on #30 thinking that it was the same exception, but had misread the stacktrace the first time through. My quick diagnosis was also flawed. Looking more deeply, I think the root of the bug is a race where onComplete() is called in between where provideChannelContext() sets state to IDLE and when subscriber.onSubscribe() gets around to setting the subscriber. That's the only window in which state could be DEMANDING or IDLE and subscriber could be null that I can see. There's not a simple fix to that race, so I think the null check in onComplete is probably the best solution for now.

Consider buffering HTTP request bodies

Due to the crossing of thread contexts involved with reactive streams, it can be expensive to process small bodies with a reactive streams implementation, it would be a lot faster if the body was passed along with the HTTP header (as part of the FullHttpRequest). The HTTP streams handler could do this by, if the Content-Length is less than a configured threshold, buffer it and emit it in a FullHttpRequest.

CVE-2019-20444-There is a security vulnerability issue in netty-reactive-streams

Hi,

Till netty-reactive-streams: 2.0.5 we have below critical security vulnerabilities identified by NVD,

CVE-2019-20444
HttpObjectDecoder.java in Netty before 4.1.44 allows an HTTP header that lacks a colon, which might be interpreted as a separate header with an incorrect syntax, or might be interpreted as an "invalid fold."

CVE-2019-20445
HttpObjectDecoder.java in Netty before 4.1.44 allows a Content-Length header to be accompanied by a second Content-Length header, or by a Transfer-Encoding header.

{
feed: "vulnerabilities",
feed_group: "nvd",
fix: "None",
nvd_data: [
{
cvss_v2: {
base_score: 6.4,
exploitability_score: 10,
impact_score: 4.9
},
cvss_v3: {
base_score: 9.1,
exploitability_score: 3.9,
impact_score: 5.2
},
id: "CVE-2019-20444"
}
],
package: "netty-reactive-streams-http-2.0.5",
package_cpe: "None",
package_cpe23: "cpe:2.3:a:netty:netty:2.0.5:*:*:*:*:*:*:*",
package_name: "netty-reactive-streams-http",
package_path: "/srv/XXX:BOOT-INF/lib/netty-reactive-streams-http-2.0.5.jar",
package_type: "java",
package_version: "2.0.5",
severity: "Critical",
url: "https://nvd.nist.gov/vuln/detail/CVE-2019-20444",
vendor_data: [ ],
vuln: "CVE-2019-20444",
will_not_fix: false
}

Seems like this was reported long ago and still the issue was not fixed in netty-reactive-streams. Do we have any information about the fix for the above vulnerabilities?

Provide library as OSGi bundle

It would be very cool to provide this library as OSGi bundle in order to use it together with other OSGi libraries.

This is quite easy with maven:

..
<packaging>bundle</packaging>
..

<build>
      <plugins>
         <plugin>
            <groupId>org.apache.felix</groupId>
            <artifactId>maven-bundle-plugin</artifactId>
            <extensions>true</extensions>
            <configuration>
               <instructions>
                  <Export-Package>com.typesafe.netty</Export-Package>
                  <_noee>true</_noee>
                  <Bundle-RequiredExecutionEnvironment>JavaSE-1.7</Bundle-RequiredExecutionEnvironment>
               </instructions>
            </configuration>
         </plugin>
      ...

License problems

Hi
Not available LICENSE file in source directory structure
Please. Added license and copyright notice.
the fedora pakaging guideline is very strictly precise about this problem
https://fedoraproject.org/wiki/Packaging:LicensingGuidelines?rd=Packaging/LicensingGuidelines#License_Text

The following source files are without license headers:

./netty-reactive-streams/src/main/java/com/typesafe/netty/CancelledSubscriber.java
./netty-reactive-streams/src/main/java/com/typesafe/netty/HandlerPublisher.java
./netty-reactive-streams/src/main/java/com/typesafe/netty/HandlerSubscriber.java

./netty-reactive-streams/src/test/java/com/typesafe/netty/BatchedProducer.java
./netty-reactive-streams/src/test/java/com/typesafe/netty/ChannelPublisherTest.java
./netty-reactive-streams/src/test/java/com/typesafe/netty/ClosedLoopChannel.java
./netty-reactive-streams/src/test/java/com/typesafe/netty/HandlerPublisherVerificationTest.java
./netty-reactive-streams/src/test/java/com/typesafe/netty/HandlerSubscriberBlackboxVerificationTest.java
./netty-reactive-streams/src/test/java/com/typesafe/netty/HandlerSubscriberWhiteboxVerificationTest.java
./netty-reactive-streams/src/test/java/com/typesafe/netty/ProbeHandler.java
./netty-reactive-streams/src/test/java/com/typesafe/netty/ScheduledBatchedProducer.java
./netty-reactive-streams/src/test/java/com/typesafe/netty/probe/Probe.java
./netty-reactive-streams/src/test/java/com/typesafe/netty/probe/SubscriberProbe.java
./netty-reactive-streams/src/test/java/com/typesafe/netty/probe/PublisherProbe.java

./netty-reactive-streams-http/src/main/java/com/typesafe/netty/http/DefaultStreamedHttpRequest.java
./netty-reactive-streams-http/src/main/java/com/typesafe/netty/http/DefaultStreamedHttpResponse.java
./netty-reactive-streams-http/src/main/java/com/typesafe/netty/http/DefaultWebSocketHttpResponse.java
./netty-reactive-streams-http/src/main/java/com/typesafe/netty/http/DelegateHttpMessage.java
./netty-reactive-streams-http/src/main/java/com/typesafe/netty/http/DelegateHttpRequest.java
./netty-reactive-streams-http/src/main/java/com/typesafe/netty/http/DelegateHttpResponse.java
./netty-reactive-streams-http/src/main/java/com/typesafe/netty/http/DelegateStreamedHttpRequest.java
./netty-reactive-streams-http/src/main/java/com/typesafe/netty/http/DelegateStreamedHttpResponse.java
./netty-reactive-streams-http/src/main/java/com/typesafe/netty/http/EmptyHttpRequest.java
./netty-reactive-streams-http/src/main/java/com/typesafe/netty/http/EmptyHttpResponse.java
./netty-reactive-streams-http/src/main/java/com/typesafe/netty/http/HttpStreamsClientHandler.java
./netty-reactive-streams-http/src/main/java/com/typesafe/netty/http/HttpStreamsHandler.java
./netty-reactive-streams-http/src/main/java/com/typesafe/netty/http/HttpStreamsServerHandler.java
./netty-reactive-streams-http/src/main/java/com/typesafe/netty/http/StreamedHttpMessage.java
./netty-reactive-streams-http/src/main/java/com/typesafe/netty/http/StreamedHttpRequest.java
./netty-reactive-streams-http/src/main/java/com/typesafe/netty/http/StreamedHttpResponse.java
./netty-reactive-streams-http/src/main/java/com/typesafe/netty/http/WebSocketHttpResponse.java

./netty-reactive-streams-http/src/test/java/com/typesafe/netty/http/AkkaStreamsUtil.java
./netty-reactive-streams-http/src/test/java/com/typesafe/netty/http/DelegateProcessor.java
./netty-reactive-streams-http/src/test/java/com/typesafe/netty/http/FullStackHttpIdentityProcessorVerificationTest.java
./netty-reactive-streams-http/src/test/java/com/typesafe/netty/http/HttpHelper.java
./netty-reactive-streams-http/src/test/java/com/typesafe/netty/http/HttpStreamsTest.java
./netty-reactive-streams-http/src/test/java/com/typesafe/netty/http/ProcessorHttpClient.java
./netty-reactive-streams-http/src/test/java/com/typesafe/netty/http/ProcessorHttpServer.java
./netty-reactive-streams-http/src/test/java/com/typesafe/netty/http/WebSocketsTest.java

Please, confirm the licensing of code and/or content/s, and add license headers
https://fedoraproject.org/wiki/Packaging:LicensingGuidelines?rd=Packaging/LicensingGuidelines#License_Clarification

Thanks in advance
Regards

HandlerSubscriber is racy (at least as used from RxJava)

I've been trying to hunt down a race condition that happens in AHC on Travis (can't reproduce locally).

AHC uses RxJava (2.1.7) as a reactive streams implementation for tests.

From io.reactivex.internal.subscribers.StrictSubscriber#onSubscribe:

actual.onSubscribe(this);
SubscriptionHelper.deferredSetOnce(this.s, requested, s);

HandlerSubscriber#onSubscribe schedule provideSubscription to be executed from the channel's EventLoop, that will trigger requesting the subscription. But SubscriptionHelper.deferredSetOnce can also request the subscription. As a consequence, we might be requesting the Publisher concurrently from multiple threads (the calling thread and the event loop one), which causes chunks to be written out of order.

I have no idea if it's a RxJava bug, or if StrictPublisher behaves according to the spec.

cc @jroper

Add an Automatic-Module-Name manifest entry

It is recommended for java libraries in public repositories like Maven Central to add Automatic-Module-Name manifest entry. This allows the consumers of the library to move to Java 9 modularization and depend on the Automatic-Module-Name value instead of the name derived from the Jar file. This way, your consumers won't need to make changes when your library is eventually converted to a Java 9 module.

Adding Automatic-Module-Name doesn't affect any code and will simply make a name reservation until an actual module-info.java will be added eventually. More details can be found in this article.

As for the module name, I think com.typesafe.netty seems reasonable. This article has best naming practices for JPMS modules.

AWS Java SDK v2 has a dependency on your library and we are adding module-info files to our library. But we need this change to be done before we can add move to JPMS. I can create a PR if you think it would be helpful to prioritize this request.

NPE in HandlerSubscriber in Play 2.5.9

From playframework/playframework#7166

2017-03-19 00:58:35,217 [netty-event-loop-14] ERROR p.c.server.netty.PlayRequestHandler - Exception caught in Netty
java.lang.NullPointerException: null
	at com.typesafe.netty.HandlerSubscriber.maybeRequestMore(HandlerSubscriber.java:271)
	at com.typesafe.netty.HandlerSubscriber.channelWritabilityChanged(HandlerSubscriber.java:130)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelWritabilityChanged(AbstractChannelHandlerContext.java:438)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelWritabilityChanged(AbstractChannelHandlerContext.java:420)
	at io.netty.channel.AbstractChannelHandlerContext.fireChannelWritabilityChanged(AbstractChannelHandlerContext.java:413)
	at io.netty.channel.ChannelInboundHandlerAdapter.channelWritabilityChanged(ChannelInboundHandlerAdapter.java:119)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelWritabilityChanged(AbstractChannelHandlerContext.java:438)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelWritabilityChanged(AbstractChannelHandlerContext.java:420)
	at io.netty.channel.AbstractChannelHandlerContext.fireChannelWritabilityChanged(AbstractChannelHandlerContext.java:413)
	at io.netty.channel.ChannelInboundHandlerAdapter.channelWritabilityChanged(ChannelInboundHandlerAdapter.java:119)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelWritabilityChanged(AbstractChannelHandlerContext.java:438)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelWritabilityChanged(AbstractChannelHandlerContext.java:420)
	at io.netty.channel.AbstractChannelHandlerContext.fireChannelWritabilityChanged(AbstractChannelHandlerContext.java:413)
	at io.netty.channel.ChannelInboundHandlerAdapter.channelWritabilityChanged(ChannelInboundHandlerAdapter.java:119)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelWritabilityChanged(AbstractChannelHandlerContext.java:438)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelWritabilityChanged(AbstractChannelHandlerContext.java:420)
	at io.netty.channel.AbstractChannelHandlerContext.fireChannelWritabilityChanged(AbstractChannelHandlerContext.java:413)
	at io.netty.channel.DefaultChannelPipeline$HeadContext.channelWritabilityChanged(DefaultChannelPipeline.java:1317)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelWritabilityChanged(AbstractChannelHandlerContext.java:438)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelWritabilityChanged(AbstractChannelHandlerContext.java:420)
	at io.netty.channel.DefaultChannelPipeline.fireChannelWritabilityChanged(DefaultChannelPipeline.java:923)
	at io.netty.channel.ChannelOutboundBuffer$2.run(ChannelOutboundBuffer.java:583)
	at io.netty.util.concurrent.SingleThreadEventExecutor.runAllTasks(SingleThreadEventExecutor.java:408)
	at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:441)
	at io.netty.util.concurrent.SingleThreadEventExecutor$2.run(SingleThreadEventExecutor.java:140)
	at java.lang.Thread.run(Thread.java:745)

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.