Code Monkey home page Code Monkey logo

bondy-io / bondy Goto Github PK

View Code? Open in Web Editor NEW
112.0 7.0 12.0 9.79 MB

Bondy is an open source, always-on and scalable application networking platform connecting all elements of a distributed application—offering service and event mesh capabilities combined. Bondy implements the open Web Application Messaging Protocol (WAMP) and is written in Erlang.

Home Page: https://www.bondy.io

License: Apache License 2.0

Makefile 0.33% Erlang 99.18% Shell 0.15% Dockerfile 0.35%
erlang microservices api-gateway rpc iot wamp-protocol service-mesh service-discovery router publish-subscribe

bondy's Introduction

Bondy logo

Version
Docker Pulls Docker Build (master) Docker Build (develop) Docker Build (latest-tag)
Architectures

Bondy

The distributed application networking platform

Bondy is an open source, always-on and scalable application networking platform connecting all elements of a distributed application—offering service and event mesh capabilities combined.

From web and mobile apps to IoT devices and backend microservices, Bondy allows everything to talk using one simple and secured communication protocol in a decoupled and dynamic way.

Bondy implements the open Web Application Messaging Protocol (WAMP).



drawing



Documentation

For our work-in-progress documentation for v1.0.0 go to https://developer.bondy.io.

Supported WAMP features

Authentication

  • Anonymous
  • Cryptosign
  • Ticket
  • WAMP-CRA
  • WAMP-SCRAM (WIP)
  • Cookie

In addition Bondy provides:

  • HTTP OAuth2
  • HTTP Password
  • Same Sign-on -- use a single set of credentials to sign on to multiple realms
  • Single Sign-on -- combines Same Sign-on with Ticket authentication. The resulting ticket can be used to sign on to multiple realms.

Advanced RPC features

  • Call Canceling
  • Call Timeouts
  • Call Trust Levels
  • Caller Identification
  • Pattern-based registration
  • Shared Registration
    • Load Balancing
      • Random
      • Round robin
    • Hot Stand-by
      • First
      • Last
  • Payload Passthru Mode (WIP)
  • Registration Revocation (WIP)
  • Progressive Call Results
  • Progressive Calls

Advanced Pub/Sub features

  • Event Retention
  • Pattern-based Subscriptions
  • Publication Trust Levels
  • Publisher Exclusion
  • Publisher Identification
  • Subscriber Black- and Whitelisting
  • Payload Passthru Mode (WIP)
  • Sharded Subscriptions
  • Subscription Revocation

Transport

  • WebSockets
  • RawSockets
  • E2E encryption

Transport Serialization

  • JSON
  • Msgpack
  • BERT
  • Erlang (subset)
  • JSON batched
  • Msgpack batched

How is Bondy different than other WAMP routers?

Bondy provides a unique combination of features which sets it apart from other application networking solutions and WAMP routers in terms of scalability, reliability, high-performance, development and operational simplicity.

  • Distributed by design – As opposed to other WAMP Router implementations, Bondy was designed as a reliable distributed router, ensuring continued operation in the event of node or network failures through clustering and data replication.
  • Scalability – Bondy is written in Erlang/OTP which provides the underlying operating system to handle concurrency and scalability requirements, allowing Bondy to scale to thousands and even millions of concurrent connections on a single node. Its distributed architecture also allows for horizontal scaling by simply adding nodes to the cluster.
  • Decentralised peer-to-peer master-less clustering – All nodes in a Bondy cluster are equal, thanks to the underlying clustering and networking technology which provides a decentralised master-less architecture. This includes all nodes acting as relays enabling Transparent routing. All nodes can also act as Bridge Relays to enable per-realm inter-cluster routing (aka Bondy Edge [Experimental]).
  • Transparent routing - Bondy will route any Caller/Publisher (sender) messages to any Callee/Subscriber (receiver) regardless of their session location in the cluster. When using Full Mesh topology (default), this results in a single hop between sender and receiver. When using the upcoming Peer-to-Peer topology this results in one or multiple hops between sender and receiver.
  • Low latency data replication – All nodes in a Bondy cluster share a global state which is replicated through a highly scalable and low latency eventually consistency model which combines causality tracking, real-time epidemic broadcasting (gossip) and periodic active anti-entropy. Bondy uses Partisan), a high-performance Distributed Erlang replacement that enables various network topologies and supports large clusters (Partisan has been demonstrated to scale up to 1,024 Erlang nodes, and provide better scalability and reduced latency than Distributed Erlang).
  • Ease of use – Bondy is easy to operate due to its operational simplicity enabled by its peer-to-peer nature, the lack of special nodes, automatic data replication and self-healing.
  • Embedded HTTP API Gateway – Bondy embeds a powerful API Gateway that can translate HTTP actions to WAMP routed RPC and PubSub operations. The API Gateway leverages the underlying storage and replication technology to deploy the API Specifications to the cluster nodes in real-time.
  • Embedded Identity Management & Authentication - Each realm manages user identity and authentication using multiple WAMP and HTTP authentication methods. Identity data is replicated across the cluster to ensure always-on and low-latency operations.
  • Embedded Role-based Access Control (RBAC) – Each realm embeds a RBAC subsystem controlling access to realm resources and authorizing message routing through the definition of groups and the assignment of permissions. RBAC data is replicated across the cluster to ensure always-on and low-latency operations.
  • Embedded Broker Bridge – Bondy embeds a Broker Bridge that can manage a set of WAMP subscribers that re-publish WAMP events to an external non-WAMP system e.g. another message broker (Kafka Bridge implemented).

Quick Start

Docker

The fastest way to get started is by using our official docker images.

  1. Make sure you have Docker installed and running.
  2. Download the examples/custom_config folder to a location of your choice, then cd to that location and run the following command (If you already cloned the Bondy repository then just cd to the location of the repo).
docker run \
--rm \
-e [email protected] \
-e BONDY_ERL_DISTRIBUTED_COOKIE=bondy \
-u 0:1000 \
-p 18080:18080 \
-p 18081:18081 \
-p 18082:18082 \
-p 18083:18083 \
-p 18084:18084 \
-p 18085:18085 \
-v "$(PWD)/examples/custom_config/etc:/bondy/etc" \
-v "/tmp/data:/bondy/data" \
leapsight/bondy:master

Building from source

Requirements

  • macOS (Intel|Apple Silicon) or Linux (amd64|arm64)
  • Erlang 26.0.2 or later
  • Rebar3 3.22.1 or later
  • openssl
  • libssl
  • Libsodium - if installing on Apple Silicon and having an issue compiling the libary check the last response on this Github Issue
  • libsnappy
  • liblz4
  • libcrypto

Building

Clone this repository and cd to the location where you cloned it.

To generate a Bondy release to be used in production execute the following command which will generate a tarball containing the release at $(PWD)/_build/prod/rel/.

make release

Untar and copy the resulting tarball to the location where you want to install Bondy e.g. ~/tmp/bondy.

tar -zxvf _build/prod/rel/bondy-1.0.0-rc.13.tar.qz -C ~/tmp/bondy

Running

To run Bondy, cd to the location where you installed it e.g. ~/tmp/bondy and run the following command which will print all the options.

bin/bondy

For example, to run Bondy with output to stdout do

bin/bondy foreground

And to run Bondy with an interactive Erlang shell do

bin/bondy console

Local cluster testing

Run a first node

We will start a node named [email protected] which uses the following variables from the config file (config/test/node_1_vars.config).

Transport Description Port
HTTP REST API GATEWAY 18080
HTTP REST API GATEWAY 18083
HTTP REST Admin API 18081
HTTPS REST Admin API 18084
Websockets WAMP 18080
TCP WAMP Raw Socket 18082
TLS WAMP Raw Socket 18085
make node1

Create a Realm

WAMP is a session-based protocol. Each session belongs to a Realm.

curl -X "POST" "http://localhost:18081/realms/" \
     -H 'Content-Type: application/json; charset=utf-8' \
     -H 'Accept: application/json; charset=utf-8' \
     -d $'{
  "uri": "com.myrealm",
  "description": "My First Realm"
}'

Disable Security

We will disable security to avoid setting up credentials at this moment.

curl -X "DELETE" "http://localhost:18081/realms/com.myrealm/security_enabled" \
     -H 'Content-Type: application/json; charset=utf-8' \
     -H 'Accept: application/json; charset=utf-8'

Run a second node

We start a second node named [email protected] which uses the following variables from the config file (config/test/node_2_vars.config).

Transport Description Port
HTTP REST API GATEWAY 18180
HTTP REST API GATEWAY 18183
HTTP REST Admin API 18181
HTTPS REST Admin API 18184
Websockets WAMP 18180
TCP WAMP Raw Socket 18182
TLS WAMP Raw Socket 18185
make node2

After a minute the two nodes will automatically connect. From now on all new Bondy control plane state changes will be propagated in real-time through broadcasting. One minute after joining the cluster, the Active Anti-entropy service will trigger an exchange after which the Realm we have created in [email protected] will have been replicated to [email protected].

Run a third node

make node3

Resources


Copyright by Leapsight, material licensed under the CC-BY-SA 4.0, provided as-is without any warranties, Bondy documentation (https://developer.bondy.io).

bondy's People

Contributors

alan-ls avatar alejandro-miguez avatar aramallo avatar frepond avatar jbucar avatar jopie64 avatar linthar avatar om26er 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

bondy's Issues

Error when running docker command

===> BONDY_TMP_DIR=./tmp
===> [info] validate-config Validating configuration files
escript: exception error: bad argument
in function io:format/2
called as io:format("~s===> [info] validate-config No Bondy configuration file found at ~p. Bondy will use the default configuration. Otherwise please make sure a 'bondy.conf' file (or 'bondy.conf.template' in case environment variables replacement is required) is present in the ~p directory.sn",
["\e[0m","./etc","\e[0m"])
*** argument 1: wrong number of arguments

Cannot run Bondy after tag 1.0.0-beta.20

I'm trying to upgrade my Bondy test system to the newest version. However, I'm unable to get it running. Installed Erlang 24 and rebar 3.18 and did just a git clone in a clean directory. Then builded Bondy and what I try I always get the errors below:

=SUPERVISOR REPORT==== 8-Feb-2022::15:00:46.987911 ===
    supervisor: {local,kernel_sup}
    errorContext: start_error
    reason: {on_load_function_failed,eleveldb}
    offender: [{pid,undefined},
               {id,kernel_safe_sup},
               {mfargs,{supervisor,start_link,
                                   [{local,kernel_safe_sup},kernel,safe]}},
               {restart_type,permanent},
               {significant,false},
               {shutdown,infinity},
               {child_type,supervisor}]

=CRASH REPORT==== 8-Feb-2022::15:00:46.988817 ===
  crasher:
    initial call: supervisor:kernel/1
    pid: <0.1286.0>
    registered_name: []
    exception exit: {on_load_function_failed,eleveldb}
      in function  init:run_on_load_handlers/0 
      in call from kernel:init/1 (kernel.erl, line 189)
      in call from supervisor:init/1 (supervisor.erl, line 330)
      in call from gen_server:init_it/2 (gen_server.erl, line 423)
      in call from gen_server:init_it/6 (gen_server.erl, line 390)
    ancestors: [kernel_sup,<0.1259.0>]
    message_queue_len: 1
    messages: [{'$gen_call',
                      {<0.1283.0>,#Ref<0.285832514.3068919809.86262>},
                      {start_child,
                          {disk_log_sup,
                              {disk_log_sup,start_link,[]},
                              permanent,1000,supervisor,
                              [disk_log_sup]}}}]
    links: [<0.1261.0>]
    dictionary: []
    trap_exit: true
    status: running
    heap_size: 610
    stack_size: 29
    reductions: 234
  neighbours:

=CRASH REPORT==== 8-Feb-2022::15:00:47.991002 ===
  crasher:
    initial call: application_master:init/4
    pid: <0.1258.0>
    registered_name: []
    exception exit: {{shutdown,
                         {failed_to_start_child,kernel_safe_sup,
                             {on_load_function_failed,eleveldb}}},
                     {kernel,start,[normal,[]]}}
      in function  application_master:init/4 (application_master.erl, line 142)
    ancestors: [<0.1257.0>]
    message_queue_len: 1
    messages: [{'EXIT',<0.1259.0>,normal}]
    links: [<0.1257.0>,<0.1256.0>]
    dictionary: []
    trap_exit: true
    status: running
    heap_size: 376
    stack_size: 29
    reductions: 165
  neighbours:

=INFO REPORT==== 8-Feb-2022::15:00:47.992281 ===
    application: kernel
    exited: {{shutdown,
                 {failed_to_start_child,kernel_safe_sup,
                     {on_load_function_failed,eleveldb}}},
             {kernel,start,[normal,[]]}}
    type: permanent

{"Kernel pid terminated",application_controller,"{application_start_failure,kernel,{{shutdown,{failed_to_start_child,kernel_safe_sup,{on_load_function_failed,eleveldb}}},{kernel,start,[normal,[]]}}}"}
Kernel pid terminated (application_controller) ({application_start_failure,kernel,{{shutdown,{failed_to_start_child,kernel_safe_sup,{on_load_function_failed,eleveldb}}},{kernel,start,[normal,[]]}}})

Crash dump is being written to: erl_crash.dump...done
make: *** [Makefile:78: node1] Error 1

The first report seems something to do with leveldb? During compilation I get this message about leveldb:

Cloning into 'leveldb'...
Note: switching to '2.0.36'.

You are in 'detached HEAD' state. You can look around, make experimental
changes and commit them, and you can discard any commits you make in this
state without impacting any branches by switching back to a branch.

If you want to create a new branch to retain commits you create, you may
do so (now or later) by using -c with the switch command. Example:

  git switch -c <new-branch-name>

Or undo this operation with:

  git switch -

Turn off this advice by setting config variable advice.detachedHead to false

HEAD is now at 14c57fe correct code in the 32bit path to correctly compile
Submodule 'leveldb_ee' (https://github.com/basho/leveldb_ee) registered for path 'leveldb_ee'

What am I missing here?

Expose all the Bondy Admin WAMP API Procedures via HTTP

At the moment not all the Admin WAMP API procedures are available via the Admin HTTP API.

Realm

  • bondy.realm.createPOST /realms
  • bondy.realm.getGET /realms/:realm_uri
  • bondy.realm.updatePUT /realms/:realm_uri
  • bondy.realm.listGET /realms
  • bondy.realm.deleteDELETE /realms/:realm_uri
  • bondy.realm.security.is_enabledGET /realms/:realm_uri/security_enabled
  • bondy.realm.security.enablePUT /realms/:realm_uri/security_enabled
  • bondy.realm.security.disableDELETE /realms/:realm_uri/security_enabled

User

  • bondy.user.addPOST /realms/:realm_uri/users/
  • bondy.user.deleteDELETE /realms/:realm_uri/users/:id
  • bondy.user.getGET /realms/:realm_uri/users/:id
  • bondy.user.updatePUT /realms/:realm_uri/users/:id/
  • bondy.user.listGET /realms/:realm_uri/users/
  • bondy.user.is_enabledGET /realms/:realm_uri/users/:id/enabled
  • bondy.user.enablePUT /realms/:realm_uri/users/:id/enabled
  • bondy.user.disableDELETE /realms/:realm_uri/users/:id/enabled
  • bondy.user.change_password -> POST /realms/:realm_uri/users/:id/change_password
  • bondy.user.add_aliasPUT /realms/:realm_uri/users/:id/aliases/:alias
  • bondy.user.remove_aliasDELETE /realms/:realm_uri/users/:id/aliases/:alias
  • bondy.user.add_groupPUT /realms/:realm_uri/users/:id/groups/:group
  • bondy.user.remove_groupDELETE /realms/:realm_uri/users/:id/groups/:group
  • bondy.user.add_groups
  • bondy.user.remove_groups

Group

  • bondy.group.addPOST /realms/:realm_uri/gropus
  • bondy.group.add_group
  • bondy.group.add_groups
  • bondy.group.deleteDELETE /realms/:realm_uri/groups/:id
  • bondy.group.getGET /realms/:realm_uri/groups/:id
  • bondy.group.list
  • bondy.group.remove_group
  • bondy.group.remove_groups
  • bondy.group.updatePUT /realms/:realm_uri/groups/:id

Source

  • bondy.source.add
  • bondy.source.delete
  • bondy.source.get
  • bondy.source.list
  • bondy.source.match

Grant

See #22.

Session

  • wamp.session.get

Ticket

  • bondy.ticket.revoke_all

OAuth2 Token

Cluster

Bridge Relay (Edge)

  • bondy.router.bridge.add
  • bondy.router.bridge.remove
  • bondy.router.bridge.start
  • bondy.router.bridge.stop
  • bondy.router.bridge.get
  • bondy.router.bridge.list
  • bondy.router.bridge.status
  • bondy.router.bridge.check_spec

HTTP API Gateway

  • bondy.http_gateway.api.add
  • bondy.http_gateway.api.getGET /api_specs/:id | GET /api_specs/:id/info
  • bondy.http_gateway.api.list -> GET /api_specs
  • bondy.http_gateway.api.load -> POST /api_specs
  • bondy.http_gateway.api.delete

Cannot add a user to a authentication source of a realm

Background: I want to add a new user through the http-api on port 18081. I'm using Postman for that (local install).

I'm able to add a user to a realm with a password or cryptosign key and add it to a group. But when I try to login I always get the message

ClientSession left: CloseDetails(reason=<wamp.error.not_auth_method>, message='The requested authentication methods are not available for this user on this realm.')

Looking at my default security_config.json I find a section called sources where the different authentication methods are defined and usernames linked to an authentication method. For cryptosign, I have to add the new user to the list of usernames. I cannot get sources through the api and I don't know add the new user. Also it's nowhere in the documentation and not specified in https://github.com/bondy-io/bondy/blob/develop/apps/bondy/priv/specs/bondy_admin_api.json

So the question is, how can this be done in a running Bondy instance?

[beta.30] login with wamp and password crashes the process.

I have beta.30 working but my Python clients which were able to connect to earlier versions cannot connect anymore. This clients are using a username and password combination, but the login crashes with:

([email protected])1>
when=2022-02-14T09:59:29.015218+00:00 level=info pid=<0.3071.0> at=: description="Established connection with peer" realm=undefined session_id=3Ezrdsy3ggRpC0p1DCzUiN8jYOt peername=127.0.0.1:58564 transport=websocket serializer=msgpack protocol=wamp frame_type=binary agent=undefined 
when=2022-02-14T09:59:29.028526+00:00 level=error pid=<0.3071.0> at=bondy_wamp_protocol:handle_inbound_messages/2:358 reason=badarg state_name=closed stacktrace="[{erlang,iolist_to_binary,[undefined],[{error_info,#{module => erl_erts_errors}}]},{crypto,mac_init,3,[{file,\"crypto.erl\"},{line,702}]},{pbkdf2,'-resolve_mac_func/1-fun-0-',3,[{file,\"/home/bondytest/Erlang/erl_24/bondy/_build/default/lib/pbkdf2/src/pbkdf2.erl\"},{line,140}]},{pbkdf2,pbkdf2,8,[{file,\"/home/bondytest/Erlang/erl_24/bondy/_build/default/lib/pbkdf2/src/pbkdf2.erl\"},{line,125}]},{pbkdf2,pbkdf2,7,[{file,\"/home/bondytest/Erlang/erl_24/bondy/_build/default/lib/pbkdf2/src/pbkdf2.erl\"},{line,104}]},{pbkdf2,pbkdf2,5,[{file,\"/home/bondytest/Erlang/erl_24/bondy/_build/default/lib/pbkdf2/src/pbkdf2.erl\"},{line,61}]},{bondy_password_cra,salted_password,3,[{file,\"/home/bondytest/Erlang/erl_24/bondy/apps/bondy/src/bondy_password_cra.erl\"},{line,183}]},{bondy_password_cra,verify_string,3,[{file,\"/home/bondytest/Erlang/erl_24/bondy/apps/bondy/src/bondy_password_cra.erl\"},{line,88}]}]" class=error 
when=2022-02-14T09:59:29.028855+00:00 level=error pid=<0.3071.0> at=: description="Process crashed" reason=badarg realm=undefined session_id=3Ezrdsy3ggRpC0p1DCzUiN8jYOt peername=127.0.0.1:58564 transport=websocket serializer=msgpack protocol=wamp frame_type=binary class=error agent=undefined 

Cannot enable or disable users in realm

I get an error when I want to enable or disable a user. Using wick from the documentation

/wick --url ws://localhost:18080/ws \
--realm com.leapsight.bondy \
call bondy.realm.security.disable "com.leapsight.test_creation_1"

I get

FATA[0000] got errors:
- calling remote procedure 'bondy.user.disable': bondy.error.function_clause: : code=function_clause, description=, message= 

Using curl

curl -X "POST" "http://localhost:18081/services/call"
  -H 'Content-Type: application/json; charset=utf-8'
  -H 'Accept: application/json; charset=utf-8'
  -d $'{
    "procedure": "bondy.user.enable",
    "options": {},
    "args": [
      "com.leapsight.test",
      "peer1"
    ],
    "kwargs": {}
  }'

I get

{"args":[""],"details":{},"error_uri":"bondy.error.function_clause","kwargs":{"code":"function_clause","description":"","message":""}}

Digging / tracing through the code and trying to debug, the error comes from:

disable(RealmUri, #{type := ?USER_TYPE} = User) ->
case update(RealmUri, User, #{enabled => false}) of
{ok, _} -> ok;
Error -> Error
end.

The problem is that the User send is a Binary and it seems that the function is expecting something different. Removing the type check will fix the problem and I can enable and disable an user. But I don't think that's the right thing to do right? I suppose it should be fixed in

handle_call(?BONDY_USER_ENABLE, #call{} = M, Ctxt) ->

All the above happens for both enable and disable an user.

User update APIs wrongly assume a credential has changed

When updating a user using one of the bondy.user.* APIs the event bondy.user.credentials_changed will be publish which triggers the session shutdown, even when the credentials have not changed.

The issue is caused by a wrong condition check in `bondy_rbac_user:have_credentials_changed/2

[1.0.0-beta.68] OAuth2 - client_credentials should not return refresh token?

At Latam LoJack we are upgrading to the latest version of bondy 1.0.0-beta.68 and We noticed that the refresh_token is not present when we issuing a new token for grant_type=client_credentials.
Due to the "BackOffice" webapps are using and implementing the oauth2 flow, we need the refresh token. Below an issued token without the refresh_token attribute:

  • Request:
curl --location --request POST 'https://..../oauth/token' \
--header 'Authorization: Basic ....' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'grant_type=client_credentials'
  • Response:
{
    "access_token": "....",
    "expires_in": 900,
    "scope": "admin,api_clients",
    "token_type": "bearer"
}

The change was applied with the following commit: 0d2e672 changing a private function in module bondy_oauth2:

%% @private
supports_refresh_token(client_credentials) -> false;
supports_refresh_token(application_code) -> true;
supports_refresh_token(password) -> true;
supports_refresh_token(Grant) -> error({oauth2_unsupported_grant_type, Grant}).

Is possible to support it? maybe using some configurable feature?

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.