> ## Documentation Index
> Fetch the complete documentation index at: https://docs.orbitflare.com/llms.txt
> Use this file to discover all available pages before exploring further.

# gRPC İstemcisi (Yellowstone)

> Otomatik yeniden bağlanma, ping/pong canlılık tespiti ve tiplenmiş filtrelerle Yellowstone Geyser akışı.

## Kurulum

```bash theme={null}
go get github.com/orbitflare/orbitflare-sdk-go
```

```go theme={null}
import "github.com/orbitflare/orbitflare-sdk-go/geyser"
```

## İstemciyi oluşturma

Tüm seçenekleri ayarlanmış bir istemci:

```go theme={null}
import (
    "time"

    "github.com/orbitflare/orbitflare-sdk-go/geyser"
    "github.com/orbitflare/orbitflare-sdk-go/orbitflare"
)

client, err := geyser.NewBuilder().
    URL("http://ny.rpc.orbitflare.com:10000").
    FallbackURL("http://fra.rpc.orbitflare.com:10000").
    Retry(orbitflare.RetryPolicy{
        InitialDelay: 100 * time.Millisecond,
        MaxDelay:     30 * time.Second,
        Multiplier:   2.0,
        MaxAttempts:  0,
    }).
    Timeout(30 * time.Second).
    Keepalive(60 * time.Second).
    PingInterval(10 * time.Second).
    MaxMissedPongs(3).
    ChannelCapacity(4096).
    Build()
```

Minimal kurulum:

```go theme={null}
client, err := geyser.NewBuilder().
    URL("http://ny.rpc.orbitflare.com:10000").
    Build()
```

gRPC için API anahtarı gerekmez. URL, `ORBITFLARE_GRPC_URL` ortam değişkenine düşer.

### Builder yöntemleri

**`.URL(url)`** - Birincil gRPC uç noktası. `ORBITFLARE_GRPC_URL`'e düşer. Düz metin HTTP/2 için `http://`, TLS için `https://` kullanın.

```go theme={null}
.URL("http://ny.rpc.orbitflare.com:10000")
```

**`.URLs(urls...)`** - Birincil + yedekler tek çağrıda. İlk eleman birincildir.

```go theme={null}
.URLs("http://ny.rpc.orbitflare.com:10000", "http://fra.rpc.orbitflare.com:10000")
```

**`.FallbackURL(url)` / `.FallbackURLs(urls...)`** - Yedek uç noktalar ekler. Bağlantı başarısız olduğunda SDK aralarında döner.

```go theme={null}
.FallbackURL("http://fra.rpc.orbitflare.com:10000")
```

**`.Retry(policy)`** - Yeniden bağlanma backoff'unu denetler. Bağlantı koptuğunda SDK `InitialDelay` bekler, sonra her denemede gecikmeyi çarpar (`MaxDelay` ile sınırlı). `MaxAttempts` 0 ise sonsuz yeniden deneme. Varsayılan: 100 ms başlangıç, 30 s maksimum, 2x çarpan, sonsuz.

```go theme={null}
.Retry(orbitflare.RetryPolicy{
    InitialDelay: 200 * time.Millisecond,
    MaxDelay:     15 * time.Second,
    Multiplier:   2.0,
    MaxAttempts:  0,
})
```

**`.Timeout(duration)`** - Bağlantı/çevirme zaman aşımı. Varsayılan 30 s.

```go theme={null}
.Timeout(15 * time.Second)
```

**`.Keepalive(duration)`** - TCP/HTTP2 keepalive aralığı; ölü bağlantıları taşıma katmanında tespit etmek için kullanılır. Varsayılan 60 s.

```go theme={null}
.Keepalive(30 * time.Second)
```

**`.PingInterval(duration)`** - SDK'nın sunucuya protokol düzeyinde `Ping` mesajlarını ne sıklıkta gönderdiği. Sunucu `Pong` ile yanıt vermelidir. Varsayılan 10 s.

```go theme={null}
.PingInterval(15 * time.Second)
```

**`.MaxMissedPongs(n)`** - SDK bağlantıyı ölü sayıp yeniden bağlanmadan önce kaç ardışık ping'in yanıtsız kalabileceği. Varsayılan 3. Varsayılanlarla ölü bir bağlantı 30 saniye içinde tespit edilir.

```go theme={null}
.MaxMissedPongs(5)
```

**`.ChannelCapacity(n)`** - Arka plan goroutine'i ile kodunuz arasındaki sınırlı kanal. Kodunuz olayları yavaş tüketiyorsa, bu dolduğunda arka plan goroutine'i sınırsız bellek tüketmek yerine bloklanır. Varsayılan 4096.

```go theme={null}
.ChannelCapacity(8192)
```

**`.Logger(logger)`** - Bağlantı yaşam döngüsü olayları için bir `*slog.Logger`. Ayarlanmazsa `ORBITFLARE_LOG` ile denetlenir.

## Abonelik oluşturma

Filtreler, `SubscribeRequestBuilder` ve tiplenmiş filtre türleriyle programatik olarak oluşturulur. Bir işlem, herhangi bir `AccountInclude` adresini içeriyorsa eşleşir; `AccountExclude` eşleşmeleri çıkarır; `AccountRequired` listelenen tüm adreslerin bulunmasını gerektirir.

```go theme={null}
request := geyser.NewSubscribeRequestBuilder().
    Transactions("pumpfun", geyser.NewTransactionFilter().
        Vote(false).
        Failed(false).
        AccountInclude("6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P")).
    Accounts("usdc-holders", geyser.NewAccountFilter().
        Owner("TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA").
        Datasize(165).
        Memcmp(geyser.MemcmpBase58(0, "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v")).
        Lamports(geyser.LamportsGt(0))).
    Slots("slots", geyser.NewSlotFilter().FilterByCommitment(true)).
    Commitment(geyser.Confirmed).
    Build()
```

### Filtre türleri

* **`NewTransactionFilter()`** - `Vote(bool)`, `Failed(bool)`, `Signature(string)`, `AccountInclude(...)`, `AccountExclude(...)`, `AccountRequired(...)`.
* **`NewAccountFilter()`** - `Account(...)`, `Owner(...)`, `Datasize(uint64)`, `TokenAccountState(bool)`, `Memcmp(...)`, `Lamports(...)`, `NonemptyTxnSignature(bool)`.
* **`NewSlotFilter()`** - `FilterByCommitment(bool)`, `InterslotUpdates(bool)`.
* **`NewBlockFilter()`** - `AccountInclude(...)`, `IncludeTransactions(bool)`, `IncludeAccounts(bool)`, `IncludeEntries(bool)`.
* **`NewDeshredTransactionFilter()`** - `Vote(bool)`, `AccountInclude(...)`, `AccountExclude(...)`, `AccountRequired(...)`.

`Memcmp`; `geyser.MemcmpBytes(offset, []byte)`, `geyser.MemcmpBase58(offset, string)` veya `geyser.MemcmpBase64(offset, string)` ile oluşturulur. `Lamports`; `geyser.LamportsEq/Ne/Lt/Gt(uint64)` ile. `Commitment`; `geyser.Processed`, `geyser.Confirmed`, `geyser.Finalized` değerlerinden biridir.

Elle oluşturmayı tercih ederseniz `Subscribe`, ham bir `*geyser.SubscribeRequest`'i (proto türünün yeniden dışa aktarımı) da kabul eder.

## Akışı okuma

`Subscribe`, bir `*geyser.Stream` döndürür. Sonraki güncellemeyi almak için `Next(ctx)` çağırın:

```go theme={null}
stream := client.Subscribe(request)
defer stream.Close()

for {
    update, err := stream.Next(ctx)
    if errors.Is(err, io.EOF) {
        break // akış kapandı
    }
    if err != nil {
        break // ölümcül: tüm yeniden denemeler tükendi
    }

    switch {
    case update.GetTransaction() != nil:
        tx := update.GetTransaction()
        // tx.GetSlot(), tx.GetTransaction() (imza, hesaplar, komutlar, meta)
    case update.GetAccount() != nil:
        acct := update.GetAccount()
        // acct.GetSlot(), acct.GetAccount() (pubkey, lamports, owner, data), acct.GetIsStartup()
    case update.GetSlot() != nil:
        slot := update.GetSlot()
        // slot.GetSlot(), slot.GetStatus()
    case update.GetBlockMeta() != nil:
        meta := update.GetBlockMeta()
        // meta.GetSlot(), meta.GetBlockhash(), meta.GetParentSlot()
    }
}
```

`Next(ctx)`, bir olay gelene kadar bloklanır. Akış bittiğinde (`Close` sonrası dahil) `io.EOF` döner; diğer her nil olmayan hata o akış için ölümcüldür. Context iptal edilirse ayrıca `ctx.Err()` döner. Pong mesajları içeride tüketilir ve akışınızda asla görünmez.

### Kapatma

```go theme={null}
stream.Close()
```

Arka plan goroutine'ini hemen durdurur. `client.Close()`, istemcinin başlattığı her akışı durdurur.

## Birden çok akış

Bir istemci aynı anda birçok akış yürütebilir. Her biri kendi arka plan bağlantısına sahiptir:

```go theme={null}
pumpfun := client.Subscribe(pumpfunReq)
raydium := client.Subscribe(raydiumReq)
slots := client.Subscribe(slotsReq)
```

Uç nokta sağlık durumunu paylaşırlar: bir akış başarısız bir uç noktayı karantinaya alırsa, diğerleri bir sonraki yeniden bağlanmada onu atlar. Ancak bağlantıları ve yaşam döngüleri tamamen bağımsızdır. İstediğiniz zaman yeni akışlar başlatabilirsiniz.

## Tam örnek

pump.fun işlemlerini izleyip her biri için bir özet yazdıran bir akış.

```go theme={null}
package main

import (
    "context"
    "errors"
    "fmt"
    "io"
    "log"

    "github.com/orbitflare/orbitflare-sdk-go/geyser"
)

func main() {
    client, err := geyser.NewBuilder().
        URL("http://ny.rpc.orbitflare.com:10000").
        FallbackURL("http://fra.rpc.orbitflare.com:10000").
        Build()
    if err != nil {
        log.Fatal(err)
    }
    defer client.Close()

    request := geyser.NewSubscribeRequestBuilder().
        Transactions("pumpfun", geyser.NewTransactionFilter().
            Vote(false).
            Failed(false).
            AccountInclude("6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P")).
        Slots("slots", geyser.NewSlotFilter().FilterByCommitment(true)).
        Commitment(geyser.Confirmed).
        Build()

    stream := client.Subscribe(request)
    defer stream.Close()

    ctx := context.Background()
    var count int
    fmt.Println("streaming...")

    for {
        update, err := stream.Next(ctx)
        if errors.Is(err, io.EOF) {
            return
        }
        if err != nil {
            log.Fatal(err)
        }

        switch {
        case update.GetTransaction() != nil:
            count++
            tx := update.GetTransaction()
            fmt.Printf("#%d slot=%d\n", count, tx.GetSlot())
        case update.GetSlot() != nil:
            s := update.GetSlot()
            fmt.Printf("slot %d (%s)\n", s.GetSlot(), s.GetStatus())
        }
    }
}
```
