Git Product home page Git Product logo

go-libp2p-daemon's Introduction

libp2p Daemon

GoDoc Discourse posts

A standalone deployment of a libp2p host, running in its own OS process and installing a set of virtual endpoints to enable co-local applications to: communicate with peers, handle protocols, interact with the DHT, participate in pubsub, etc. no matter the language they are developed in, nor whether a native libp2p implementation exists in that language.

๐Ÿšง This project is not actively maintained and is unsupported! ๐Ÿšง

It has reached viable PoC stage but is not being actively worked on or maintained. If you want to play around with libp2p, go ahead and try this project out. However:

  • There is little documentation and no support.
  • The libp2p version used in this project will not be actively updated.

In other words: DO NOT USE IN PRODUCTION

Install

This repo uses Go modules. Note that go >=1.12 is required.

$ # outside your GOPATH
$ git clone https://github.com/libp2p/go-libp2p-daemon
$ cd go-libp2p-daemon
$ git checkout <release tag, e.g. v0.0.1>
$ go get ./...
$ go install ./...
$ p2pd

See available releases.

Usage

Check out the GoDocs.

Language Bindings

Daemon bindings enable applications written in other languages to interact with the libp2p daemon process programmatically, by exposing an idiomatic API that handles the socket dynamics and control protocol.

The following bindings exist so far (if you want yours added, please send a PR):

If you wish to implement bindings in a new language, refer to the spec for the daemon control protocol and API.

Contribute

Feel free to join in. All welcome. Open an issue!

This repository falls under the IPFS Code of Conduct.

License

MIT


The last gx published version of this module was: 0.0.20: QmVBYP5AGurRJGiyTcyoUf5Etyvf2vwxKd8DMaQgbpJF58

go-libp2p-daemon's People

Contributors

aarshkshah1992 avatar achingbrain avatar anacrolix avatar bigs avatar ckousik avatar dependabot-preview[bot] avatar hsanjuan avatar jacobheun avatar kubuxu avatar lanzafame avatar libp2p-mgmt-read-write[bot] avatar lnykww avatar marcopolo avatar mhchia avatar mvid avatar raulk avatar stebalien avatar timjp87 avatar vyzo avatar web-flow avatar web3-bot avatar yusefnapora 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

Watchers

 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

go-libp2p-daemon's Issues

Panic on launch with gossipsub

I'm at d161fe580fc98d62a8ba961df5ac0e70a76fc71d.

After go build inside /p2pd and then:

./p2pd -pubsub=true -pubsubRouter=gossipsub

I get this:

Control socket: /unix/tmp/p2pd.sock
Peer ID: QmPi2mpZuaq2w7ZDQxXXnGr4WwJo7tv8eoLs64roVFyZ9N
Peer Addrs:
panic: non-positive interval for NewTicker

goroutine 32 [running]:
time.NewTicker(0x0, 0xc00007dea0)
        /go/1.12.1/libexec/src/time/tick.go:23 +0x190
github.com/libp2p/go-libp2p-pubsub.(*GossipSubRouter).heartbeatTimer(0xc000048180)
        /go/pkg/mod/github.com/libp2p/[email protected]/gossipsub.go:365 +0x14a
created by github.com/libp2p/go-libp2p-pubsub.(*GossipSubRouter).Attach
        /go/pkg/mod/github.com/libp2p/[email protected]/gossipsub.go:76 +0x52

Support for QUIC transport

This would be useful for many ongoing research efforts. Adding an option for QUIC would potentially get more teams testing/contributing to the daemon.

Listen flag is confusing

We use the listen flag to control socket. There's also a noListenAddrs which specifies "don't listen on any libp2p transports". There's also an option hostAddrs which specifies which libp2p transports/addresses we should listen on.

We should change this to:

  • -control, or -controlSocket, etc. for the control address.
  • listenAddrs and noListenAddrs for libp2p listen addresses.

Topic validator functions in pubsub

It seems like application-provided validator functions for pubsub are not implemented yet. I think we had discussed this is something want. Ethereum 2.0 will likely use it.

Disconnect from peer.

I see here present connect(peer, addresses) and recently added feature trim() (which drops connections to all connected peers), but i don't see any ability to disconnect from particular peer. Is this feature is missing or not needed?

IDENTIFY method response.

p2pd output on start is:

Control socket: /tmp/p2pd.sock
Peer ID: QmcvboYSXDy3QBGsk21HbNdiXssq7S4EgRAMyPPAXmFCr1
Peer Addrs:
/p2p-circuit
/ip4/127.0.0.1/tcp/37091
/ip4/192.168.58.131/tcp/37091
/ip6/::1/tcp/45191

IDENTIFY method response in binary form

08 00 22 52 0A 22 12 20 D8 B6 14 0E 76 4F 49 7A
0A F9 E1 C3 C5 88 E9 B0 5D 41 44 5A F9 6C 1E 8A
CC CB D2 86 3C DA AE 96 12 14 29 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 01 06 B0 87 12 02
A2 02 12 08 04 7F 00 00 01 06 90 E3 12 08 04 C0
A8 3A 83 06 90 E3

Peer ID in binary form

12 20 D8 B6 14 0E 76 4F 49 7A 0A F9 E1 C3 C5 88
E9 B0 5D 41 44 5A F9 6C 1E 8A CC CB D2 86 3C DA
AE 96

IPv6 address

29 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
01 06 B0 87

Unknown address, i could not find any information about this type of address, could you please explain it?

A2 02

IPv4 address

04 7F 00 00 01 06 90 E3

IPv4 address

04 C0 A8 3A 83 06 90 E3

Add support for configuration via file/stdin

As the daemon grows our configuration flag options are likely to become cumbersome pretty quickly. I was talking with @bigs and @vasco-santos about needing to add support for specifying the multiaddrs the daemons libp2p node listens on. We could, and probably should, add a comma delimited string flag similar to how we add bootstrap addresses. Over time though, reading through all of the flags you have enabled for a node could get overwhelming.

I'd like to propose adding support for piping a config file to the daemon. For example:

$ cat config.json | p2p daemon

This would also have the nice benefit of being able to have node type configurations pre made for users; DHT booster, relay, rendezvous, etc.

If this sounds good, I can write up a spec for the json configuration.

`Stream.reset`?

Is it possible to reset a stream which we get from STREAM_OPEN or STREAM_HANDLER? I scanned the codebase and couldn't find it out. It seems we can only close the stream for now.

Cannot build xerrors on MacOS go1.13

Following the instructions doesn't work on MacOS with go1.13:

git clone https://github.com/libp2p/go-libp2p-daemon
cd go-libp2p-daemon/
git checkout c4c3f318
go get ./...
go: finding golang.org/x/text v0.3.0
go: finding github.com/jackpal/go-nat-pmp v1.0.1
go: finding github.com/koron/go-ssdp v0.0.0-20180514024734-4a0ed625a78b
go: finding golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522
# golang.org/x/xerrors
../../../go/pkg/mod/golang.org/x/[email protected]/adaptor_go1_13.go:16:14: undefined: errors.Frame
../../../go/pkg/mod/golang.org/x/[email protected]/format_go1_13.go:12:18: undefined: errors.Formatter

Upstream: golang/go#32246

and workaround: golang/go#32246 (comment)

golang.org/x/xerrors v0.0.0-20190528162220-0421b64034aa

Design discussion

Opening a thread for the discussion of the control API for our daemon.

Control API

Responsibilities

  • Peerstore management
  • Stream creation (connect if connection does not exist)
  • General information retrieval
    • Open connections
    • Open streams
    • Peerstore size
  • Register protocol handlers

Implementation details

Two solid options:

  • HTTP/JSON
    • Requires polling for incoming connections
  • JSON over TCP
    • Bidirectional, so we can push incoming stream notices to users

Stream Proxy

Responsibilities

  • Proxy streams to end users, taking care of all security (secio, TLS) and multiplexing (yamux, etc)
  • Clients should be able to close streams (i.e. close a file handle)
  • Incoming streams on registered protocols should create new streams

Implementation details

Editor's note: I think we can get away by polling the filesystem/shared memory where our streams are created as opposed to polling the control API, which would make things simpler.

  • Unix sockets
    • One socket per stream
    • Organized on filesystem by connection id
    • Seems Windows support has landed
  • shmem
    • Likely fastest implementation
    • Certainly most complex, least platform agnostic
      • There exists a Windows alternative, but it has a separate API. Perhaps something to be dealt with in a golang library
  • Proxy Filesystems (FUSE, WinFSP)
    • Heavier than unix sockets

Any instruction? Examples?

Are there instructions / examples? Brief search did not get results (I did not try to build it though).

Missing module with go 1.12

Error with v0.2.3 and go version 1.12:

build github.com/libp2p/go-libp2p-daemon/p2p-keygen: cannot find module for path crypto/ed25519 

Per readme, 1.12 should be supported. Worked with go1.13

Running with configuration file

I tried using this link, https://github.com/libp2p/go-libp2p-daemon/blob/master/specs/CONFIG.md, to test how to running configuration, but I got error message.
$ p2pd -f ./DO.json 2021/02/16 11:52:18 failed to parse multiaddr "\"/unix/tmp/p2pd.sock\"": must begin with /

How would I get this issue resolved? And is it possible to have something like the below in configuration file?

{ 
  "ID": "Qma3GsJmB47xYuyahPZPSadh1avvxfyYQwk8R3UnFrQ6aP"
  "PublicKey": 'xxxxxxxxx',
  "PrivateKey" : "yyyyyyyyyy",
}

Thanks

Print stats/diagnostics on system signal

For debugging the state of the daemon, it could be useful to add a hook to catch SIGUSR2 (as we plan to use SIGUSR1 for config reload) that prints statistics/diagnostics to stdout/stderr.

We can output at least:

  • dht.RoutingTable.Print()
  • active connections with peers.
  • active streams with peers, including the protocol id.
  • pubsub subscriptions.

For now, the DHT routing table would suffice, as we actually do need it kind of immediately.

Allow for control over TCP socket

In order to leverage the daemon for purposes of integration testing and the testbed more generally, we need to have remote-dialable daemons. I'd vote for abstracting the listen path into a multiaddr (similarly, client listen paths should be multiaddrs) and adding support to dial unix sockets to go-multiaddr-net.

Windows IPC support

During devcon4 workshops, somebody suggested to use Named Pipes in Windows, as the Unix domain socket support is experimental. Suggested steps:

  • Have somebody test the daemon as-is in Windows Insider Build 17063 or above, and report on results. Comment on this issue if you're up.
  • Investigate https://github.com/Microsoft/go-winio, a Go wrapper for native Windows IO operations, maintained by Microsoft.
  • Implement the changes to support this as a local transport for IPC.

quic module compiling error

go get ./...
go get: warning: modules disabled by GO111MODULE=auto in GOPATH/src;
	ignoring go.mod;
	see 'go help modules'
# github.com/libp2p/go-libp2p-quic-transport
../go-libp2p-quic-transport/stream.go:15:31: s.Stream.CancelRead(0) used as value
../go-libp2p-quic-transport/stream.go:18:29: s.Stream.CancelWrite(0) used as value
../go-libp2p-quic-transport/transport.go:22:62: undefined: quic.VersionMilestone0_10_0

Print version information in help / --version

p2pd -version now prints a generic help, but it's impossible to know what version of the source code it was built from - preferably git hash + tagged release or something would be nice.

Graceful shutdown

In particular, daemons should clean up any unix sockets it may have created after trapping SIGINT.

Motivation

Why do we need a libp2p daemon and what do we want it to do?

Remove secio usage as default connection encryption

Now that we officially deprecated secio as a connection encryption module for libp2p, we should remove it from the daemon. Making noise used by default and remove the option to use secio/noise at all.

Currently, we are running interop tests for libp2p using secio unless explicitly setting noise, which is not desirable.

We should this together with libp2p/js-libp2p-daemon#43 to update the interop tests to use the new daemons with noise

cc @jacobheun @aschmahmann

Fix tests on windows

Now that we have multiaddr support for control sockets, which allows us to use tcp, we should finally fix the tests on windows.
Tired of those red Xs!

Resurrect project by updating go-libp2p version

This project is remarkably useful for basic interop testing between go-libp2p and js-libp2p, but the go-libp2p version is out of date so we can't test recent features like the wan/lan dual-dht, yamux, etc.

A great little starter task would be to update go-libp2p in this project.

Howto connect to daemon

Hi there! I am playing around with the daemon and started writing a client in Rust. I tried opening the unix socket and sent protobuf encoded messages (identify and find peer), but the daemon does not seem to respond at all. Is there some initialization procedure I am missing or something?

I assume it to work this way:

  1. Connect to unix socket
  2. Send commands (length delimited?)
  3. Get responses

Should it work this way?

Organising option flags

As users demand more functionalities (e.g. #34), we're likely to see a proliferation of option flags for the daemon binary. While the daemon is marked as an experimental project, we should attempt to bring in structure to our option flags. Let's agree on an approach and lock it in.

Proposal:

  • Let's be idiomatic. I found that camelCasing flags is not really idiomatic in Go: go test uses no casing or separators, and ipfs uses hyphens. My proposal is to use hyphens.
  • Let's namespace our flags.
  • Let's strive for consistency. Consistency can look different in each namespace, e.g. for transports, we can make all flags additive (a flag adds support for a transport), and provide a single subtractive flag to disable OOTB defaults. The connection manager deals with values, so it'll look different.

For transports, this can look as follows:

-tpt-enable-quic        enables the QUIC transport
-tpt-enable-ws          enables the WebSockets transport
-tpt-enable-tcp         enables the TCP transport
-tpt-disable-defaults   disables the default transports 

So if I wanted to enable ONLY QUIC, I'd do the following:

p2pd -tpt-disable-defaults -tpt-enable-quic

WDYT? CC @vyzo @bigs @jrhea @cheatfate @mhchia

Bad error message when running p2pd with no arguments

> ./p2pd
2021/03/15 11:40:50 if we explicitly specify a transport, we must also explicitly specify the listen addrs
  1. I didn't specify a transport...
  2. Listen addrs? Which listen addrs? I assume this means the daemon control address (one, not multiple).

Expose the Peerstore

Expose the Peerstore to allow daemon clients to access that information, such as known protocols a peer supports.

I'm proposing an addition of protos to the PeerInfo protobuf. This would enable us to expose the known protocols of a peer to consuming clients during the LIST_PEERS request.

Daemon as shared library.

In most of the cases daemon usage is fine, but sometimes your project could not spawn actual daemon executable. Is it possible to wrap the daemon inside of simple shared library, this library can export for example just two functions start(configuration) and stop().

So when application loads shared library and calls to start(configuration) daemon's main() function will be executed in new thread (or in any other possible ways). In such case all the named sockets created will be inside of application, so it can be possible to use daemon in iOS (for example).

This is of course not priority issue, but it would be very handy to have such feature.

Crash on daemon shutdown

The clean exit logic is not so clean after all, it panics on systemd shutdown:

May 03 08:51:16 ip-172-31-45-199 systemd[1]: Stopping libp2p relay...
May 03 08:51:16 ip-172-31-45-199 relay.sh[14745]: 08:51:16.786 ERROR       p2pd: error accepting connection: accept unix /var/run/p2pd/p2pd.sock: use of closed network connection daemon.go:142
May 03 08:51:16 ip-172-31-45-199 relay.sh[14745]: 08:51:16.786 ERROR       p2pd: error accepting connection: accept unix /var/run/p2pd/p2pd.sock: use of closed network connection daemon.go:142
May 03 08:51:16 ip-172-31-45-199 relay.sh[14745]: panic: runtime error: invalid memory address or nil pointer dereference
May 03 08:51:16 ip-172-31-45-199 relay.sh[14745]: [signal SIGSEGV: segmentation violation code=0x1 addr=0x0 pc=0x9e4287]
May 03 08:51:16 ip-172-31-45-199 relay.sh[14745]: goroutine 2019 [running]:
May 03 08:51:16 ip-172-31-45-199 relay.sh[14745]: github.com/libp2p/go-libp2p-daemon.(*Daemon).handleConn(0xc00013a540, 0x0, 0x0)
May 03 08:51:16 ip-172-31-45-199 relay.sh[14745]:         /home/ubuntu/go/src/github.com/libp2p/go-libp2p-daemon/conn.go:22 +0x37
May 03 08:51:16 ip-172-31-45-199 relay.sh[14745]: created by github.com/libp2p/go-libp2p-daemon.(*Daemon).listen
May 03 08:51:16 ip-172-31-45-199 relay.sh[14745]:         /home/ubuntu/go/src/github.com/libp2p/go-libp2p-daemon/daemon.go:146 +0x98
May 03 08:51:16 ip-172-31-45-199 relay.sh[14745]: panic: runtime error: invalid memory address or nil pointer dereference
May 03 08:51:16 ip-172-31-45-199 relay.sh[14745]: [signal SIGSEGV: segmentation violation code=0x1 addr=0x0 pc=0x9e4287]
May 03 08:51:16 ip-172-31-45-199 relay.sh[14745]: goroutine 2023 [running]:
May 03 08:51:16 ip-172-31-45-199 relay.sh[14745]: github.com/libp2p/go-libp2p-daemon.(*Daemon).handleConn(0xc00013a540, 0x0, 0x0)
May 03 08:51:16 ip-172-31-45-199 relay.sh[14745]:         /home/ubuntu/go/src/github.com/libp2p/go-libp2p-daemon/conn.go:22 +0x37
May 03 08:51:16 ip-172-31-45-199 relay.sh[14745]: created by github.com/libp2p/go-libp2p-daemon.(*Daemon).listen
May 03 08:51:16 ip-172-31-45-199 relay.sh[14745]:         /home/ubuntu/go/src/github.com/libp2p/go-libp2p-daemon/daemon.go:146 +0x98
May 03 08:51:16 ip-172-31-45-199 systemd[1]: relay.service: Main process exited, code=exited, status=2/INVALIDARGUMENT
May 03 08:51:16 ip-172-31-45-199 systemd[1]: relay.service: Failed with result 'exit-code'.

cc @mvid @bigs

Concurrency models to support with native language bindings

Opening this issue to continue the discussion we started regarding what concurrency models that should be supported when targeting language level bindings.

Asynchronous Model

Concurrency handled on the Go client side. Async calls from Java/Python/C etc that require a response are tracked with an id. There are two ways we could handle this:
1) Java/Python/C could poll the Go client until the matching response id is returned
2) Java/Python/C could provide a function pointer and the Go client could issue a callback when the response is ready.

I prefer option 2 here

Synchronous Model

There might be cases where we want to provide a synchronous mode of interaction. This might be useful for simulations where we want things to happen during each timestep for the purpose of research and reporting the health of the network given different simulated pathological scenarios.

Just a thought. I am curious what you guys think

Usage Documentation

There's a "spec" in specs/CONFIG.md but it doesn't actually say how to use a config.

There's also a useless "go read the go docs" comment in the README.

We need to replace the Usage section in the README with a short section on how to get started:

  1. How to setup a config with a persistent ID.
  2. How to start p2pd.

DHT requests before bootstrap.

At the moment, the client application can not find out when the bootstrap process is completed enough to execute such commands as PROVIDE or FIND_PROVIDERS.
In such case it is possible to get error from daemon failed to find any peer in table.

I understand that bootstrap process is working in the background. Is it possible to block result of PROVIDE until DHT will be able to perform this request. Because client application is unable to know when its safe to call PROVIDE.

DHT validator / selector

I am writing the interop tests for the DHT between js and go and I am having an issue with the keys.

Using js-ipfs and go-ipfs daemon, we are able to put / get any type of keys, while it doesn't seem to be the case with go-libp2p. In this context, I think that we should be able to set custom validators/selectors as we are able to do when using the DHT module. Moreover, regarding testing the interop between get and put will be more complex since we would have to use a valid namespace such as ipns and put a valid record.

Example in go tests for custom validators/selectors: libp2p/go-libp2p-kad-dht/dht_test.go#L51

Unexpected behavior when trying to connect to bootstrap nodes

We want to set up our custom network so that machines under NAT can still connect to each other. We tried providing our bootstrap nodes, but they didn't return the public address of our under-NAT machines.

Then we tried providing nodes from this go-libp2p example and encountered some strange behavior: when providing only one of the peers nothing works (either we can't connect, or the peer doesn't return the public IP), but when providing both everything works just fine.

What could be the issue? Could the issue be with how we configure our nodes? If yes, what options do we need to specify, so the peers return the public addresses of other nodes?

photo_2021-03-12_21-27-20

Network notifiee callbacks

I'm thinking if it makes sense to let the daemon register a network notifiee which has both Connected and Disconnected exposed to the clients in some way(e.g. through the socket which the client is listening). It will allow the clients to be called back right after connected and disconnected events. This is not necessary because we can do it through polling with list_peers.

The advantage I can think of now is we can perform handshaking or blacklist checking right after connecting, and be updated when peers have disconnected. The drawback is that it incurs additional complexity to do the callbacks in both the daemon and client.

License

What license will this be released under? MIT, Apache 2? Do you mind adding that to the repo?

`key` is `string` type in `GET_VALUE`, `PUT_VALUE`, `SEARCH_VALUE` DHT requests

I was trying to PUT_VALUE with the value from GET_PUBLIC_KEY, and the key of Multihash(value, sha2_256). I needed to convert the key bytes to string in advance because there will be error when we feed a non-UTF8 encoded bytes to the string field. E.g.

dht_req = p2pd_pb.DHTRequest(
    type= p2pd_pb.DHTRequest.PUT_VALUE,
    key=key_bytes,  # error: should be unicode string, instead of non UTF-8 encoded bytes
    value=value,
)
`ValueError: b'/pk/\x12 B\xbe\x80\x01\xe9\xc8\x15\xf6D\xa0W\x89\xb2\x86\xb1\xe0\x99\xd5U\xa6\xf9\x99\xc9\xe1\x0e\xd0\xcbhx\xfbt\xb4' has type str, but isn't valid UTF-8 encoding. Non-UTF-8 strings must be converted to unicode objects before being added.

So the code snippet which performs put_value looks like below in python:

    value = client.get_public_key(peer_id)
    mh_digest = multihash.digest(value, algo)
    mh_bytes = mh_digest.encode()
    key_bytes_in_str = "".join([chr(i) for i in mh_bytes])  # convert bytes to string
    key = "/pk/" + key_bytes_in_str
    client.put_value(key, value)

And I got error from the daemon: connect failed. msg=key did not contain valid multihash: multihash length inconsistent. I investigated for a while and think the problem should be the encoding in Python protobuf. The key in unicode will still be encode('utf-8'), when encoded by pbmsg.SerializeToString(), and turned into a malformatted multihash with some bigger unicode encoded to utf-8, where the content and length are changed. Therefore the daemon receives a malformatted key.

I am trying to recover the malformatted key before it is sent, and therefore the issue might be solved. Possible solutions might be

  1. Change the encode('utf-8') to encode('iso-8859-1') in the serialization. But it seems nowhere to configure it in protobuf Python. Might possibly override something to achieve this.
  2. Change the key from string to bytes.

I wonder if it makes sense to change the key in protobuf from string to bytes, if it is possibly composed of non-utf-8 encoded text like the result of hashes?

Thank you!


Notes

  • Tried to escape the non-utf8 bytes with google.protobuf.text_encoding.CEscape(b, as_utf8=False), serialize the request PB, unescape the serialized bytes back to the unescaped string, turn it to bytes again with encode('iso-8859-1'), and send the bytes. But errors still occurs when the protobuf tries to deserialize the bytes: [libprotobuf ERROR google/protobuf/wire_format_lite.cc:626] String field 'p2pd.pb.DHTRequest.key' contains invalid UTF-8 data when parsing a protocol buffer. Use the 'bytes' type if you intend to send raw bytes.

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.