moved the kafka-go project to this repository
This commit is contained in:
@@ -0,0 +1,34 @@
|
|||||||
|
[](https://app.codecrafters.io/users/Timmelmann?r=2qF)
|
||||||
|
|
||||||
|
This is a starting point for Go solutions to the
|
||||||
|
["Build Your Own Kafka" Challenge](https://codecrafters.io/challenges/kafka).
|
||||||
|
|
||||||
|
In this challenge, you'll build a toy Kafka clone that's capable of accepting
|
||||||
|
and responding to APIVersions & Fetch API requests. You'll also learn about
|
||||||
|
encoding and decoding messages using the Kafka wire protocol. You'll also learn
|
||||||
|
about handling the network protocol, event loops, TCP sockets and more.
|
||||||
|
|
||||||
|
**Note**: If you're viewing this repo on GitHub, head over to
|
||||||
|
[codecrafters.io](https://codecrafters.io) to try the challenge.
|
||||||
|
|
||||||
|
# Passing the first stage
|
||||||
|
|
||||||
|
The entry point for your Kafka implementation is in `app/server.go`. Study and
|
||||||
|
uncomment the relevant code, and push your changes to pass the first stage:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
git commit -am "pass 1st stage" # any msg
|
||||||
|
git push origin master
|
||||||
|
```
|
||||||
|
|
||||||
|
That's all!
|
||||||
|
|
||||||
|
# Stage 2 & beyond
|
||||||
|
|
||||||
|
Note: This section is for stages 2 and beyond.
|
||||||
|
|
||||||
|
1. Ensure you have `go (1.19)` installed locally
|
||||||
|
1. Run `./your_program.sh` to run your Kafka broker, which is implemented in
|
||||||
|
`app/server.go`.
|
||||||
|
1. Commit your changes and run `git push origin master` to submit your solution
|
||||||
|
to CodeCrafters. Test output will be streamed to your terminal.
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
package protocol
|
||||||
|
|
||||||
|
import "encoding/binary"
|
||||||
|
|
||||||
|
type Request struct {
|
||||||
|
bytes []byte
|
||||||
|
byteParseOffset uint
|
||||||
|
|
||||||
|
Length int32
|
||||||
|
Header *RequestHeader
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewRequest(bytes []byte) *Request {
|
||||||
|
req := Request{
|
||||||
|
bytes: bytes,
|
||||||
|
byteParseOffset: 0,
|
||||||
|
}
|
||||||
|
|
||||||
|
req.Length = req.ReadInt32()
|
||||||
|
req.Header = ParseRequestHeader(&req)
|
||||||
|
|
||||||
|
return &req
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Request) ReadInt16() int16{
|
||||||
|
val := binary.BigEndian.Uint16(r.bytes[r.byteParseOffset:])
|
||||||
|
r.byteParseOffset += 2
|
||||||
|
return int16(val)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Request) ReadInt32() int32 {
|
||||||
|
val := binary.BigEndian.Uint32(r.bytes[r.byteParseOffset:])
|
||||||
|
r.byteParseOffset += 4
|
||||||
|
return int32(val)
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
package protocol
|
||||||
|
|
||||||
|
type RequestHeader struct {
|
||||||
|
APIKey int16
|
||||||
|
APIVersion int16
|
||||||
|
Correlation_id int32
|
||||||
|
}
|
||||||
|
|
||||||
|
func ParseRequestHeader(r *Request) *RequestHeader {
|
||||||
|
apiKey := r.ReadInt16()
|
||||||
|
apiVersion := r.ReadInt16()
|
||||||
|
correlation_id := r.ReadInt32()
|
||||||
|
|
||||||
|
return &RequestHeader{
|
||||||
|
APIKey: apiKey,
|
||||||
|
APIVersion: apiVersion,
|
||||||
|
Correlation_id: correlation_id,
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
package response
|
||||||
|
|
||||||
|
type Message struct {
|
||||||
|
body []byte
|
||||||
|
header V0Header
|
||||||
|
messageSize int32
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
package response
|
||||||
|
|
||||||
|
import "encoding/binary"
|
||||||
|
|
||||||
|
type V0Header struct {
|
||||||
|
Correlation_id uint32
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewHeader(correlation_id uint32) *V0Header {
|
||||||
|
return &V0Header{
|
||||||
|
Correlation_id: correlation_id,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *V0Header) ToBytes() []byte {
|
||||||
|
buf := make([]byte, 4)
|
||||||
|
binary.BigEndian.PutUint32(buf, uint32(h.Correlation_id))
|
||||||
|
return buf
|
||||||
|
}
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
package response
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/binary"
|
||||||
|
)
|
||||||
|
|
||||||
|
type V0Response struct {
|
||||||
|
header V0Header
|
||||||
|
body []byte
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewV0Reponse(correlation_id uint32) *V0Response {
|
||||||
|
return &V0Response{
|
||||||
|
header: V0Header{
|
||||||
|
Correlation_id: correlation_id},
|
||||||
|
body: []byte{},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *V0Response) ToBytes() []byte {
|
||||||
|
header := r.header.ToBytes()
|
||||||
|
length := len(header)
|
||||||
|
buf := make([]byte, length+4)
|
||||||
|
binary.BigEndian.PutUint32(buf[0:4], uint32(length))
|
||||||
|
copy(buf[4:], header)
|
||||||
|
|
||||||
|
return buf
|
||||||
|
}
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
protocol "github.com/codecrafters-io/redis-starter-go/app/protocol/response"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Ensures gofmt doesn't remove the "net" and "os" imports in stage 1 (feel free to remove this!)
|
||||||
|
var _ = net.Listen
|
||||||
|
var _ = os.Exit
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
|
||||||
|
l, err := net.Listen("tcp", "0.0.0.0:9092")
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("Failed to bind to port 9092: ", err.Error())
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
conn, err := l.Accept()
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("Could not accept connection: ", err.Error())
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
defer conn.Close()
|
||||||
|
|
||||||
|
if _, err = conn.Read(make([]byte, 1024)); err != nil {
|
||||||
|
fmt.Println("Failed to read request: ", err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
response := protocol.NewV0Reponse(7)
|
||||||
|
if _, err = conn.Write(response.ToBytes()); err != nil {
|
||||||
|
fmt.Println("Failed to write response: ", err.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
# Set this to true if you want debug logs.
|
||||||
|
#
|
||||||
|
# These can be VERY verbose, so we suggest turning them off
|
||||||
|
# unless you really need them.
|
||||||
|
debug: false
|
||||||
|
|
||||||
|
# Use this to change the Go version used to run your code
|
||||||
|
# on Codecrafters.
|
||||||
|
#
|
||||||
|
# Available versions: go-1.22
|
||||||
|
language_pack: go-1.22
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
// DON'T EDIT THIS!
|
||||||
|
//
|
||||||
|
// Codecrafters relies on this file being intact to run tests successfully. Any changes
|
||||||
|
// here will not reflect when CodeCrafters tests your code, and might even cause build
|
||||||
|
// failures.
|
||||||
|
//
|
||||||
|
// DON'T EDIT THIS!
|
||||||
|
|
||||||
|
module github.com/codecrafters-io/redis-starter-go
|
||||||
|
|
||||||
|
go 1.22
|
||||||
Executable
+24
@@ -0,0 +1,24 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
#
|
||||||
|
# Use this script to run your program LOCALLY.
|
||||||
|
#
|
||||||
|
# Note: Changing this script WILL NOT affect how CodeCrafters runs your program.
|
||||||
|
#
|
||||||
|
# Learn more: https://codecrafters.io/program-interface
|
||||||
|
|
||||||
|
set -e # Exit early if any commands fail
|
||||||
|
|
||||||
|
# Copied from .codecrafters/compile.sh
|
||||||
|
#
|
||||||
|
# - Edit this to change how your program compiles locally
|
||||||
|
# - Edit .codecrafters/compile.sh to change how your program compiles remotely
|
||||||
|
(
|
||||||
|
cd "$(dirname "$0")" # Ensure compile steps are run within the repository directory
|
||||||
|
go build -o /tmp/codecrafters-build-redis-go app/*.go
|
||||||
|
)
|
||||||
|
|
||||||
|
# Copied from .codecrafters/run.sh
|
||||||
|
#
|
||||||
|
# - Edit this to change how your program runs locally
|
||||||
|
# - Edit .codecrafters/run.sh to change how your program runs remotely
|
||||||
|
exec /tmp/codecrafters-build-redis-go "$@"
|
||||||
Reference in New Issue
Block a user