diff --git a/go.work.sum b/go.work.sum index 74318f18..ed545b33 100644 --- a/go.work.sum +++ b/go.work.sum @@ -259,6 +259,7 @@ golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/mod v0.21.0 h1:vvrHzRwRfVKSiLrG+d4FMl/Qi4ukBCE6kZlTUkDYRT0= golang.org/x/mod v0.21.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -402,6 +403,7 @@ golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= +golang.org/x/tools v0.25.0 h1:oFU9pkj/iJgs+0DT+VMHrx+oBKs/LJMV+Uvg78sl+fE= golang.org/x/tools v0.25.0/go.mod h1:/vtpO8WL1N9cQC3FN5zPqb//fRXskFHbLKk4OW1Q7rg= google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= diff --git a/intents/intent.gen.go b/intents/intent.gen.go index 0ea952e5..540e262b 100644 --- a/intents/intent.gen.go +++ b/intents/intent.gen.go @@ -1,4 +1,4 @@ -// sequence-waas-intents v0.1.0 2e4f5d4a4107d8e8c74c252f4d1a7aad391db6e7 +// sequence-waas-intents v0.1.0 47010351881054ccb75b704db39b04ddc8837c4b // -- // Code generated by webrpc-gen@v0.19.3 with golang generator. DO NOT EDIT. // @@ -25,7 +25,7 @@ func WebRPCSchemaVersion() string { // Schema hash generated from your RIDL schema func WebRPCSchemaHash() string { - return "2e4f5d4a4107d8e8c74c252f4d1a7aad391db6e7" + return "47010351881054ccb75b704db39b04ddc8837c4b" } // @@ -51,6 +51,10 @@ const ( IntentName_removeAccount IntentName = "removeAccount" IntentName_listAccounts IntentName = "listAccounts" IntentName_getIdToken IntentName = "getIdToken" + IntentName_adoptChildWallet IntentName = "adoptChildWallet" + IntentName_getAdopter IntentName = "getAdopter" + IntentName_confirmIntent IntentName = "confirmIntent" + IntentName_getConfirmationStatus IntentName = "getConfirmationStatus" ) func (x IntentName) MarshalText() ([]byte, error) { @@ -109,23 +113,26 @@ func (x *TransactionType) Is(values ...TransactionType) bool { type IntentResponseCode string const ( - IntentResponseCode_authInitiated IntentResponseCode = "authInitiated" - IntentResponseCode_sessionOpened IntentResponseCode = "sessionOpened" - IntentResponseCode_sessionClosed IntentResponseCode = "sessionClosed" - IntentResponseCode_sessionList IntentResponseCode = "sessionList" - IntentResponseCode_validationRequired IntentResponseCode = "validationRequired" - IntentResponseCode_validationStarted IntentResponseCode = "validationStarted" - IntentResponseCode_validationFinished IntentResponseCode = "validationFinished" - IntentResponseCode_sessionAuthProof IntentResponseCode = "sessionAuthProof" - IntentResponseCode_signedMessage IntentResponseCode = "signedMessage" - IntentResponseCode_feeOptions IntentResponseCode = "feeOptions" - IntentResponseCode_transactionReceipt IntentResponseCode = "transactionReceipt" - IntentResponseCode_transactionFailed IntentResponseCode = "transactionFailed" - IntentResponseCode_getSessionResponse IntentResponseCode = "getSessionResponse" - IntentResponseCode_accountList IntentResponseCode = "accountList" - IntentResponseCode_accountFederated IntentResponseCode = "accountFederated" - IntentResponseCode_accountRemoved IntentResponseCode = "accountRemoved" - IntentResponseCode_idToken IntentResponseCode = "idToken" + IntentResponseCode_authInitiated IntentResponseCode = "authInitiated" + IntentResponseCode_sessionOpened IntentResponseCode = "sessionOpened" + IntentResponseCode_sessionClosed IntentResponseCode = "sessionClosed" + IntentResponseCode_sessionList IntentResponseCode = "sessionList" + IntentResponseCode_validationRequired IntentResponseCode = "validationRequired" + IntentResponseCode_validationStarted IntentResponseCode = "validationStarted" + IntentResponseCode_validationFinished IntentResponseCode = "validationFinished" + IntentResponseCode_sessionAuthProof IntentResponseCode = "sessionAuthProof" + IntentResponseCode_signedMessage IntentResponseCode = "signedMessage" + IntentResponseCode_feeOptions IntentResponseCode = "feeOptions" + IntentResponseCode_transactionReceipt IntentResponseCode = "transactionReceipt" + IntentResponseCode_transactionFailed IntentResponseCode = "transactionFailed" + IntentResponseCode_getSessionResponse IntentResponseCode = "getSessionResponse" + IntentResponseCode_accountList IntentResponseCode = "accountList" + IntentResponseCode_accountFederated IntentResponseCode = "accountFederated" + IntentResponseCode_accountRemoved IntentResponseCode = "accountRemoved" + IntentResponseCode_idToken IntentResponseCode = "idToken" + IntentResponseCode_adopter IntentResponseCode = "adopter" + IntentResponseCode_childWalletAdopted IntentResponseCode = "childWalletAdopted" + IntentResponseCode_confirmationRequired IntentResponseCode = "confirmationRequired" ) func (x IntentResponseCode) MarshalText() ([]byte, error) { @@ -226,6 +233,33 @@ func (x *IdentityType) Is(values ...IdentityType) bool { return false } +type ChallengeType string + +const ( + ChallengeType_EmailOTP ChallengeType = "EmailOTP" +) + +func (x ChallengeType) MarshalText() ([]byte, error) { + return []byte(x), nil +} + +func (x *ChallengeType) UnmarshalText(b []byte) error { + *x = ChallengeType(string(b)) + return nil +} + +func (x *ChallengeType) Is(values ...ChallengeType) bool { + if x == nil { + return false + } + for _, v := range values { + if *x == v { + return true + } + } + return false +} + type Intent struct { Version string `json:"version"` Name IntentName `json:"name"` @@ -337,12 +371,39 @@ type IntentDataRemoveAccount struct { AccountID string `json:"accountId"` } +type IntentDataAdoptChildWallet struct { + Network string `json:"network"` + Wallet string `json:"wallet"` + Adopter string `json:"adopter"` + AdopterProof *AdopterProof `json:"adopterProof"` +} + +type AdopterProof struct { + Message string `json:"message"` + Signature string `json:"signature"` +} + type IntentDataGetIdToken struct { SessionID string `json:"sessionId"` Wallet string `json:"wallet"` Nonce string `json:"nonce"` } +type IntentDataGetAdopter struct { + Wallet string `json:"wallet"` +} + +type IntentDataConfirmIntent struct { + Wallet string `json:"wallet"` + ConfirmationID string `json:"confirmationID"` + ChallengeAnswer string `json:"challengeAnswer"` +} + +type IntentDataGetConfirmationStatus struct { + Wallet string `json:"wallet"` + ConfirmationID string `json:"confirmationID"` +} + type TransactionRaw struct { Type string `json:"type"` To string `json:"to"` @@ -514,6 +575,22 @@ type IntentResponseIdToken struct { ExpiresIn int `json:"expiresIn"` } +type IntentResponseChildWalletAdopted struct { + AdopterAddress string `json:"adopterAddress"` +} + +type IntentResponseAdopter struct { + AdopterAddress string `json:"adopterAddress"` +} + +type IntentResponseConfirmationRequired struct { + ConfirmationID string `json:"confirmationId"` + Salt string `json:"salt"` + ChallengeType ChallengeType `json:"challengeType"` + ChallengeDestination *string `json:"challengeDestination"` + ExpiresIn int `json:"expiresIn"` +} + type Account struct { ID string `json:"id"` Type IdentityType `json:"type"` diff --git a/intents/intent.ridl b/intents/intent.ridl index 007f07eb..51899d9e 100644 --- a/intents/intent.ridl +++ b/intents/intent.ridl @@ -34,6 +34,10 @@ enum IntentName: string - removeAccount - listAccounts - getIdToken + - adoptChildWallet + - getAdopter + - confirmIntent + - getConfirmationStatus struct IntentDataInitiateAuth - sessionId: string @@ -141,6 +145,16 @@ struct IntentDataRemoveAccount - accountId: string + go.field.name = AccountID +struct IntentDataAdoptChildWallet + - network: string + - wallet: string + - adopter: string + - adopterProof: AdopterProof + +struct AdopterProof + - message: string + - signature: string + struct IntentDataGetIdToken - sessionId: string + go.field.name = SessionID @@ -148,6 +162,20 @@ struct IntentDataGetIdToken - nonce?: string + go.field.type = string +struct IntentDataGetAdopter + - wallet: string + +struct IntentDataConfirmIntent + - wallet: string + - confirmationID: string + + go.field.name = ConfirmationID + - challengeAnswer: string + +struct IntentDataGetConfirmationStatus + - wallet: string + - confirmationID: string + + go.field.name = ConfirmationID + struct TransactionRaw - type: string - to: string @@ -159,7 +187,7 @@ struct AbiData - abi: string - func?: string - args: []any - + enum TransactionType: string - transaction - erc20send @@ -232,6 +260,9 @@ enum IntentResponseCode: string - accountFederated - accountRemoved - idToken + - adopter + - childWalletAdopted + - confirmationRequired struct IntentResponseAuthInitiated - sessionId: string @@ -334,6 +365,20 @@ struct IntentResponseIdToken - idToken: string - expiresIn: int +struct IntentResponseChildWalletAdopted + - adopterAddress: string + +struct IntentResponseAdopter + - adopterAddress: string + +struct IntentResponseConfirmationRequired + - confirmationId: string + + go.field.name = ConfirmationID + - salt: string + - challengeType: ChallengeType + - challengeDestination?: string + - expiresIn: int + enum IdentityType: string - None - Guest @@ -351,3 +396,6 @@ struct Account + go.tag.json = issuer,omitempty - email?: string + go.tag.json = email,omitempty + +enum ChallengeType: string + - EmailOTP diff --git a/intents/intent_response_typed.go b/intents/intent_response_typed.go index 2591c9a0..7da6a225 100644 --- a/intents/intent_response_typed.go +++ b/intents/intent_response_typed.go @@ -36,6 +36,12 @@ func IntentResponseTypeToCode[T any](t *T) IntentResponseCode { return IntentResponseCode_accountFederated case *IntentResponseAccountRemoved: return IntentResponseCode_accountRemoved + case *IntentResponseChildWalletAdopted: + return IntentResponseCode_childWalletAdopted + case *IntentResponseAdopter: + return IntentResponseCode_adopter + case *IntentResponseConfirmationRequired: + return IntentResponseCode_confirmationRequired case *IntentResponseIdToken: return IntentResponseCode_idToken default: diff --git a/intents/intent_typed.go b/intents/intent_typed.go index 6fc89d5b..96cbe090 100644 --- a/intents/intent_typed.go +++ b/intents/intent_typed.go @@ -39,6 +39,14 @@ func IntentDataTypeToName[T any](t *T) IntentName { return IntentName_federateAccount case *IntentDataRemoveAccount: return IntentName_removeAccount + case *IntentDataAdoptChildWallet: + return IntentName_adoptChildWallet + case *IntentDataGetAdopter: + return IntentName_getAdopter + case *IntentDataConfirmIntent: + return IntentName_confirmIntent + case *IntentDataGetConfirmationStatus: + return IntentName_getConfirmationStatus case *IntentDataGetIdToken: return IntentName_getIdToken default: diff --git a/sessions/proto/sessions.gen.go b/sessions/proto/sessions.gen.go index aae0ddae..ed719361 100644 --- a/sessions/proto/sessions.gen.go +++ b/sessions/proto/sessions.gen.go @@ -1,8 +1,8 @@ -// sessions v0.0.1 d81ea64cbe41c1ab8b0107bce2f118817b34ebc0 +// sessions v0.0.1 67f782e8acfe452f905078a7423ed5d27c6639a8 // -- -// Code generated by webrpc-gen@v0.18.6 with golang generator. DO NOT EDIT. +// Code generated by webrpc-gen@v0.20.3 with golang generator. DO NOT EDIT. // -// webrpc-gen -schema=sessions.ridl -target=golang -pkg=proto -server -client -out=./sessions.gen.go +// webrpc-gen -schema=sessions.ridl -target=golang -pkg=proto -client -out=./clients/sessions.gen.go package proto import ( @@ -14,7 +14,6 @@ import ( "io" "net/http" "net/url" - "strings" "time" "github.com/0xsequence/go-sequence/lib/prototyp" @@ -32,7 +31,7 @@ func WebRPCSchemaVersion() string { // Schema hash generated from your RIDL schema func WebRPCSchemaHash() string { - return "d81ea64cbe41c1ab8b0107bce2f118817b34ebc0" + return "67f782e8acfe452f905078a7423ed5d27c6639a8" } // @@ -85,27 +84,85 @@ func (x *SignatureType) Is(values ...SignatureType) bool { } type RuntimeStatus struct { - Healthy bool `json:"healthy"` - Started time.Time `json:"started"` - Uptime uint64 `json:"uptime"` - Version string `json:"version"` - Branch string `json:"branch"` - Commit string `json:"commit"` + Healthy bool `json:"healthy"` + Started time.Time `json:"started"` + Uptime uint64 `json:"uptime"` + Version string `json:"version"` + Branch string `json:"branch"` + Commit string `json:"commit"` + Arweave *ArweaveStatus `json:"arweave"` +} + +type ArweaveStatus struct { + NodeURL string `json:"nodeURL"` + Namespace string `json:"namespace"` + Sender string `json:"sender"` + Signer string `json:"signer"` + FlushInterval string `json:"flushInterval"` + BundleDelay string `json:"bundleDelay"` + BundleLimit int `json:"bundleLimit"` + Confirmations int `json:"confirmations"` + LockTTL string `json:"lockTTL"` + Healthy bool `json:"healthy"` + LastFlush *time.Time `json:"lastFlush"` + LastFlushSeconds *uint64 `json:"lastFlushSeconds"` +} + +type Info struct { Wallets map[string]uint64 `json:"wallets"` Configs map[string]uint64 `json:"configs"` ConfigTrees uint64 `json:"configTrees"` Migrations map[string]uint64 `json:"migrations"` Signatures uint64 `json:"signatures"` Digests uint64 `json:"digests"` - Recorder *RecorderStatus `json:"recorder"` + Recorder *RecorderInfo `json:"recorder,omitempty"` + Arweave *ArweaveInfo `json:"arweave,omitempty"` } -type RecorderStatus struct { - Requests uint64 `json:"requests"` - Buffer uint64 `json:"buffer"` - LastFlush *time.Time `json:"lastFlush"` - SecondsSinceLastFlush *uint64 `json:"secondsSinceLastFlush"` - Endpoints map[string]uint64 `json:"endpoints"` +type RecorderInfo struct { + Requests uint64 `json:"requests"` + Buffer uint64 `json:"buffer"` + LastFlush *time.Time `json:"lastFlush"` + LastFlushSeconds *uint64 `json:"lastFlushSeconds"` + Endpoints map[string]uint64 `json:"endpoints"` +} + +type ArweaveInfo struct { + NodeURL string `json:"nodeURL"` + Namespace string `json:"namespace"` + Sender *ArweaveSenderInfo `json:"sender"` + Signer string `json:"signer"` + FlushInterval string `json:"flushInterval"` + BundleDelay string `json:"bundleDelay"` + BundleLimit int `json:"bundleLimit"` + Confirmations int `json:"confirmations"` + LockTTL string `json:"lockTTL"` + Healthy bool `json:"healthy"` + LastFlush *time.Time `json:"lastFlush"` + LastFlushSeconds *uint64 `json:"lastFlushSeconds"` + Bundles uint64 `json:"bundles"` + Pending *ArweavePendingInfo `json:"pending"` +} + +type ArweaveSenderInfo struct { + Address string `json:"address"` + Balance string `json:"balance"` +} + +type ArweavePendingInfo struct { + Wallets uint64 `json:"wallets"` + Configs uint64 `json:"configs"` + Migrations uint64 `json:"migrations"` + Signatures uint64 `json:"signatures"` + Bundles []*ArweaveBundleInfo `json:"bundles"` +} + +type ArweaveBundleInfo struct { + Transaction string `json:"transaction"` + Block uint64 `json:"block"` + Items uint64 `json:"items"` + SentAt time.Time `json:"sentAt"` + Confirmations uint64 `json:"confirmations"` } type Context struct { @@ -118,11 +175,20 @@ type Context struct { } type Signature struct { - Digest prototyp.Hash `json:"digest"` - ToImageHash prototyp.HashMaybe `json:"toImageHash,omitempty"` - ChainID prototyp.BigInt `json:"chainID"` - Type SignatureType `json:"type"` - Signature prototyp.Hash `json:"signature"` + Digest prototyp.Hash `json:"digest"` + ToImageHash prototyp.HashMaybe `json:"toImageHash,omitempty"` + ChainID prototyp.BigInt `json:"chainID"` + Type SignatureType `json:"type"` + Signature prototyp.Hash `json:"signature"` + ValidOnChain *prototyp.BigInt `json:"validOnChain,omitempty"` + ValidOnBlock *prototyp.BigInt `json:"validOnBlock,omitempty"` + ValidOnBlockHash prototyp.HashMaybe `json:"validOnBlockHash,omitempty"` +} + +type SignerSignature struct { + ReferenceChainID *string `json:"referenceChainID"` + Signer *string `json:"signer"` + Signature string `json:"signature"` } type ConfigUpdate struct { @@ -146,6 +212,71 @@ type TransactionBundle struct { Signature prototyp.Hash `json:"signature"` } +var ( + methods = map[string]method{ + "/rpc/Sessions/Ping": { + Name: "Ping", + Service: "Sessions", + Annotations: map[string]string{}, + }, + "/rpc/Sessions/Config": { + Name: "Config", + Service: "Sessions", + Annotations: map[string]string{}, + }, + "/rpc/Sessions/Wallets": { + Name: "Wallets", + Service: "Sessions", + Annotations: map[string]string{}, + }, + "/rpc/Sessions/DeployHash": { + Name: "DeployHash", + Service: "Sessions", + Annotations: map[string]string{}, + }, + "/rpc/Sessions/ConfigUpdates": { + Name: "ConfigUpdates", + Service: "Sessions", + Annotations: map[string]string{}, + }, + "/rpc/Sessions/Migrations": { + Name: "Migrations", + Service: "Sessions", + Annotations: map[string]string{}, + }, + "/rpc/Sessions/SaveConfig": { + Name: "SaveConfig", + Service: "Sessions", + Annotations: map[string]string{}, + }, + "/rpc/Sessions/SaveWallet": { + Name: "SaveWallet", + Service: "Sessions", + Annotations: map[string]string{}, + }, + "/rpc/Sessions/SaveSignature": { + Name: "SaveSignature", + Service: "Sessions", + Annotations: map[string]string{}, + }, + "/rpc/Sessions/SaveSignerSignatures": { + Name: "SaveSignerSignatures", + Service: "Sessions", + Annotations: map[string]string{}, + }, + "/rpc/Sessions/SaveSignerSignatures2": { + Name: "SaveSignerSignatures2", + Service: "Sessions", + Annotations: map[string]string{}, + }, + "/rpc/Sessions/SaveMigration": { + Name: "SaveMigration", + Service: "Sessions", + Annotations: map[string]string{}, + }, + } +) + var WebRPCServices = map[string][]string{ "Sessions": { "Ping", @@ -158,6 +289,7 @@ var WebRPCServices = map[string][]string{ "SaveWallet", "SaveSignature", "SaveSignerSignatures", + "SaveSignerSignatures2", "SaveMigration", }, } @@ -169,14 +301,15 @@ var WebRPCServices = map[string][]string{ type Sessions interface { Ping(ctx context.Context) error Config(ctx context.Context, imageHash string) (int, interface{}, error) - Wallets(ctx context.Context, signer string) (map[string]*Signature, error) + Wallets(ctx context.Context, signer string, cursor *uint64, limit *uint64) (map[string]*Signature, uint64, error) DeployHash(ctx context.Context, wallet string) (string, *Context, error) ConfigUpdates(ctx context.Context, wallet string, fromImageHash string, allUpdates *bool) ([]*ConfigUpdate, error) Migrations(ctx context.Context, wallet string, fromVersion int, fromImageHash string, chainID *string) (map[string]map[int]map[string]*TransactionBundle, error) SaveConfig(ctx context.Context, version int, config interface{}) error SaveWallet(ctx context.Context, version int, deployConfig interface{}) error - SaveSignature(ctx context.Context, wallet string, digest string, chainID string, signature string, toConfig *interface{}) error + SaveSignature(ctx context.Context, wallet string, digest string, chainID string, signature string, toConfig *interface{}, referenceChainID *string) error SaveSignerSignatures(ctx context.Context, wallet string, digest string, chainID string, signatures []string, toConfig *interface{}) error + SaveSignerSignatures2(ctx context.Context, wallet string, digest string, chainID string, signatures []*SignerSignature, toConfig *interface{}) error SaveMigration(ctx context.Context, wallet string, fromVersion int, toVersion int, toConfig interface{}, executor string, transactions []*Transaction, nonce string, signature string, chainID *string) error } @@ -187,556 +320,18 @@ type Sessions interface { type SessionsClient interface { Ping(ctx context.Context) error Config(ctx context.Context, imageHash string) (int, interface{}, error) - Wallets(ctx context.Context, signer string) (map[string]*Signature, error) + Wallets(ctx context.Context, signer string, cursor *uint64, limit *uint64) (map[string]*Signature, uint64, error) DeployHash(ctx context.Context, wallet string) (string, *Context, error) ConfigUpdates(ctx context.Context, wallet string, fromImageHash string, allUpdates *bool) ([]*ConfigUpdate, error) Migrations(ctx context.Context, wallet string, fromVersion int, fromImageHash string, chainID *string) (map[string]map[int]map[string]*TransactionBundle, error) SaveConfig(ctx context.Context, version int, config interface{}) error SaveWallet(ctx context.Context, version int, deployConfig interface{}) error - SaveSignature(ctx context.Context, wallet string, digest string, chainID string, signature string, toConfig *interface{}) error + SaveSignature(ctx context.Context, wallet string, digest string, chainID string, signature string, toConfig *interface{}, referenceChainID *string) error SaveSignerSignatures(ctx context.Context, wallet string, digest string, chainID string, signatures []string, toConfig *interface{}) error + SaveSignerSignatures2(ctx context.Context, wallet string, digest string, chainID string, signatures []*SignerSignature, toConfig *interface{}) error SaveMigration(ctx context.Context, wallet string, fromVersion int, toVersion int, toConfig interface{}, executor string, transactions []*Transaction, nonce string, signature string, chainID *string) error } -// -// Server -// - -type WebRPCServer interface { - http.Handler -} - -type sessionsServer struct { - Sessions - OnError func(r *http.Request, rpcErr *WebRPCError) -} - -func NewSessionsServer(svc Sessions) *sessionsServer { - return &sessionsServer{ - Sessions: svc, - } -} - -func (s *sessionsServer) ServeHTTP(w http.ResponseWriter, r *http.Request) { - defer func() { - // In case of a panic, serve a HTTP 500 error and then panic. - if rr := recover(); rr != nil { - s.sendErrorJSON(w, r, ErrWebrpcServerPanic.WithCause(fmt.Errorf("%v", rr))) - panic(rr) - } - }() - - ctx := r.Context() - ctx = context.WithValue(ctx, HTTPResponseWriterCtxKey, w) - ctx = context.WithValue(ctx, HTTPRequestCtxKey, r) - ctx = context.WithValue(ctx, ServiceNameCtxKey, "Sessions") - - var handler func(ctx context.Context, w http.ResponseWriter, r *http.Request) - switch r.URL.Path { - case "/rpc/Sessions/Ping": - handler = s.servePingJSON - case "/rpc/Sessions/Config": - handler = s.serveConfigJSON - case "/rpc/Sessions/Wallets": - handler = s.serveWalletsJSON - case "/rpc/Sessions/DeployHash": - handler = s.serveDeployHashJSON - case "/rpc/Sessions/ConfigUpdates": - handler = s.serveConfigUpdatesJSON - case "/rpc/Sessions/Migrations": - handler = s.serveMigrationsJSON - case "/rpc/Sessions/SaveConfig": - handler = s.serveSaveConfigJSON - case "/rpc/Sessions/SaveWallet": - handler = s.serveSaveWalletJSON - case "/rpc/Sessions/SaveSignature": - handler = s.serveSaveSignatureJSON - case "/rpc/Sessions/SaveSignerSignatures": - handler = s.serveSaveSignerSignaturesJSON - case "/rpc/Sessions/SaveMigration": - handler = s.serveSaveMigrationJSON - default: - err := ErrWebrpcBadRoute.WithCause(fmt.Errorf("no handler for path %q", r.URL.Path)) - s.sendErrorJSON(w, r, err) - return - } - - if r.Method != "POST" { - w.Header().Add("Allow", "POST") // RFC 9110. - err := ErrWebrpcBadMethod.WithCause(fmt.Errorf("unsupported method %q (only POST is allowed)", r.Method)) - s.sendErrorJSON(w, r, err) - return - } - - contentType := r.Header.Get("Content-Type") - if i := strings.Index(contentType, ";"); i >= 0 { - contentType = contentType[:i] - } - contentType = strings.TrimSpace(strings.ToLower(contentType)) - - switch contentType { - case "application/json": - handler(ctx, w, r) - default: - err := ErrWebrpcBadRequest.WithCause(fmt.Errorf("unexpected Content-Type: %q", r.Header.Get("Content-Type"))) - s.sendErrorJSON(w, r, err) - } -} - -func (s *sessionsServer) servePingJSON(ctx context.Context, w http.ResponseWriter, r *http.Request) { - ctx = context.WithValue(ctx, MethodNameCtxKey, "Ping") - - // Call service method implementation. - err := s.Sessions.Ping(ctx) - if err != nil { - rpcErr, ok := err.(WebRPCError) - if !ok { - rpcErr = ErrWebrpcEndpoint.WithCause(err) - } - s.sendErrorJSON(w, r, rpcErr) - return - } - - w.Header().Set("Content-Type", "application/json") - w.WriteHeader(http.StatusOK) - w.Write([]byte("{}")) -} - -func (s *sessionsServer) serveConfigJSON(ctx context.Context, w http.ResponseWriter, r *http.Request) { - ctx = context.WithValue(ctx, MethodNameCtxKey, "Config") - - reqBody, err := io.ReadAll(r.Body) - if err != nil { - s.sendErrorJSON(w, r, ErrWebrpcBadRequest.WithCause(fmt.Errorf("failed to read request data: %w", err))) - return - } - defer r.Body.Close() - - reqPayload := struct { - Arg0 string `json:"imageHash"` - }{} - if err := json.Unmarshal(reqBody, &reqPayload); err != nil { - s.sendErrorJSON(w, r, ErrWebrpcBadRequest.WithCause(fmt.Errorf("failed to unmarshal request data: %w", err))) - return - } - - // Call service method implementation. - ret0, ret1, err := s.Sessions.Config(ctx, reqPayload.Arg0) - if err != nil { - rpcErr, ok := err.(WebRPCError) - if !ok { - rpcErr = ErrWebrpcEndpoint.WithCause(err) - } - s.sendErrorJSON(w, r, rpcErr) - return - } - - respPayload := struct { - Ret0 int `json:"version"` - Ret1 interface{} `json:"config"` - }{ret0, ret1} - respBody, err := json.Marshal(respPayload) - if err != nil { - s.sendErrorJSON(w, r, ErrWebrpcBadResponse.WithCause(fmt.Errorf("failed to marshal json response: %w", err))) - return - } - - w.Header().Set("Content-Type", "application/json") - w.WriteHeader(http.StatusOK) - w.Write(respBody) -} - -func (s *sessionsServer) serveWalletsJSON(ctx context.Context, w http.ResponseWriter, r *http.Request) { - ctx = context.WithValue(ctx, MethodNameCtxKey, "Wallets") - - reqBody, err := io.ReadAll(r.Body) - if err != nil { - s.sendErrorJSON(w, r, ErrWebrpcBadRequest.WithCause(fmt.Errorf("failed to read request data: %w", err))) - return - } - defer r.Body.Close() - - reqPayload := struct { - Arg0 string `json:"signer"` - }{} - if err := json.Unmarshal(reqBody, &reqPayload); err != nil { - s.sendErrorJSON(w, r, ErrWebrpcBadRequest.WithCause(fmt.Errorf("failed to unmarshal request data: %w", err))) - return - } - - // Call service method implementation. - ret0, err := s.Sessions.Wallets(ctx, reqPayload.Arg0) - if err != nil { - rpcErr, ok := err.(WebRPCError) - if !ok { - rpcErr = ErrWebrpcEndpoint.WithCause(err) - } - s.sendErrorJSON(w, r, rpcErr) - return - } - - respPayload := struct { - Ret0 map[string]*Signature `json:"wallets"` - }{ret0} - respBody, err := json.Marshal(respPayload) - if err != nil { - s.sendErrorJSON(w, r, ErrWebrpcBadResponse.WithCause(fmt.Errorf("failed to marshal json response: %w", err))) - return - } - - w.Header().Set("Content-Type", "application/json") - w.WriteHeader(http.StatusOK) - w.Write(respBody) -} - -func (s *sessionsServer) serveDeployHashJSON(ctx context.Context, w http.ResponseWriter, r *http.Request) { - ctx = context.WithValue(ctx, MethodNameCtxKey, "DeployHash") - - reqBody, err := io.ReadAll(r.Body) - if err != nil { - s.sendErrorJSON(w, r, ErrWebrpcBadRequest.WithCause(fmt.Errorf("failed to read request data: %w", err))) - return - } - defer r.Body.Close() - - reqPayload := struct { - Arg0 string `json:"wallet"` - }{} - if err := json.Unmarshal(reqBody, &reqPayload); err != nil { - s.sendErrorJSON(w, r, ErrWebrpcBadRequest.WithCause(fmt.Errorf("failed to unmarshal request data: %w", err))) - return - } - - // Call service method implementation. - ret0, ret1, err := s.Sessions.DeployHash(ctx, reqPayload.Arg0) - if err != nil { - rpcErr, ok := err.(WebRPCError) - if !ok { - rpcErr = ErrWebrpcEndpoint.WithCause(err) - } - s.sendErrorJSON(w, r, rpcErr) - return - } - - respPayload := struct { - Ret0 string `json:"deployHash"` - Ret1 *Context `json:"context"` - }{ret0, ret1} - respBody, err := json.Marshal(respPayload) - if err != nil { - s.sendErrorJSON(w, r, ErrWebrpcBadResponse.WithCause(fmt.Errorf("failed to marshal json response: %w", err))) - return - } - - w.Header().Set("Content-Type", "application/json") - w.WriteHeader(http.StatusOK) - w.Write(respBody) -} - -func (s *sessionsServer) serveConfigUpdatesJSON(ctx context.Context, w http.ResponseWriter, r *http.Request) { - ctx = context.WithValue(ctx, MethodNameCtxKey, "ConfigUpdates") - - reqBody, err := io.ReadAll(r.Body) - if err != nil { - s.sendErrorJSON(w, r, ErrWebrpcBadRequest.WithCause(fmt.Errorf("failed to read request data: %w", err))) - return - } - defer r.Body.Close() - - reqPayload := struct { - Arg0 string `json:"wallet"` - Arg1 string `json:"fromImageHash"` - Arg2 *bool `json:"allUpdates"` - }{} - if err := json.Unmarshal(reqBody, &reqPayload); err != nil { - s.sendErrorJSON(w, r, ErrWebrpcBadRequest.WithCause(fmt.Errorf("failed to unmarshal request data: %w", err))) - return - } - - // Call service method implementation. - ret0, err := s.Sessions.ConfigUpdates(ctx, reqPayload.Arg0, reqPayload.Arg1, reqPayload.Arg2) - if err != nil { - rpcErr, ok := err.(WebRPCError) - if !ok { - rpcErr = ErrWebrpcEndpoint.WithCause(err) - } - s.sendErrorJSON(w, r, rpcErr) - return - } - - respPayload := struct { - Ret0 []*ConfigUpdate `json:"updates"` - }{ret0} - respBody, err := json.Marshal(respPayload) - if err != nil { - s.sendErrorJSON(w, r, ErrWebrpcBadResponse.WithCause(fmt.Errorf("failed to marshal json response: %w", err))) - return - } - - w.Header().Set("Content-Type", "application/json") - w.WriteHeader(http.StatusOK) - w.Write(respBody) -} - -func (s *sessionsServer) serveMigrationsJSON(ctx context.Context, w http.ResponseWriter, r *http.Request) { - ctx = context.WithValue(ctx, MethodNameCtxKey, "Migrations") - - reqBody, err := io.ReadAll(r.Body) - if err != nil { - s.sendErrorJSON(w, r, ErrWebrpcBadRequest.WithCause(fmt.Errorf("failed to read request data: %w", err))) - return - } - defer r.Body.Close() - - reqPayload := struct { - Arg0 string `json:"wallet"` - Arg1 int `json:"fromVersion"` - Arg2 string `json:"fromImageHash"` - Arg3 *string `json:"chainID"` - }{} - if err := json.Unmarshal(reqBody, &reqPayload); err != nil { - s.sendErrorJSON(w, r, ErrWebrpcBadRequest.WithCause(fmt.Errorf("failed to unmarshal request data: %w", err))) - return - } - - // Call service method implementation. - ret0, err := s.Sessions.Migrations(ctx, reqPayload.Arg0, reqPayload.Arg1, reqPayload.Arg2, reqPayload.Arg3) - if err != nil { - rpcErr, ok := err.(WebRPCError) - if !ok { - rpcErr = ErrWebrpcEndpoint.WithCause(err) - } - s.sendErrorJSON(w, r, rpcErr) - return - } - - respPayload := struct { - Ret0 map[string]map[int]map[string]*TransactionBundle `json:"migrations"` - }{ret0} - respBody, err := json.Marshal(respPayload) - if err != nil { - s.sendErrorJSON(w, r, ErrWebrpcBadResponse.WithCause(fmt.Errorf("failed to marshal json response: %w", err))) - return - } - - w.Header().Set("Content-Type", "application/json") - w.WriteHeader(http.StatusOK) - w.Write(respBody) -} - -func (s *sessionsServer) serveSaveConfigJSON(ctx context.Context, w http.ResponseWriter, r *http.Request) { - ctx = context.WithValue(ctx, MethodNameCtxKey, "SaveConfig") - - reqBody, err := io.ReadAll(r.Body) - if err != nil { - s.sendErrorJSON(w, r, ErrWebrpcBadRequest.WithCause(fmt.Errorf("failed to read request data: %w", err))) - return - } - defer r.Body.Close() - - reqPayload := struct { - Arg0 int `json:"version"` - Arg1 interface{} `json:"config"` - }{} - if err := json.Unmarshal(reqBody, &reqPayload); err != nil { - s.sendErrorJSON(w, r, ErrWebrpcBadRequest.WithCause(fmt.Errorf("failed to unmarshal request data: %w", err))) - return - } - - // Call service method implementation. - err = s.Sessions.SaveConfig(ctx, reqPayload.Arg0, reqPayload.Arg1) - if err != nil { - rpcErr, ok := err.(WebRPCError) - if !ok { - rpcErr = ErrWebrpcEndpoint.WithCause(err) - } - s.sendErrorJSON(w, r, rpcErr) - return - } - - w.Header().Set("Content-Type", "application/json") - w.WriteHeader(http.StatusOK) - w.Write([]byte("{}")) -} - -func (s *sessionsServer) serveSaveWalletJSON(ctx context.Context, w http.ResponseWriter, r *http.Request) { - ctx = context.WithValue(ctx, MethodNameCtxKey, "SaveWallet") - - reqBody, err := io.ReadAll(r.Body) - if err != nil { - s.sendErrorJSON(w, r, ErrWebrpcBadRequest.WithCause(fmt.Errorf("failed to read request data: %w", err))) - return - } - defer r.Body.Close() - - reqPayload := struct { - Arg0 int `json:"version"` - Arg1 interface{} `json:"deployConfig"` - }{} - if err := json.Unmarshal(reqBody, &reqPayload); err != nil { - s.sendErrorJSON(w, r, ErrWebrpcBadRequest.WithCause(fmt.Errorf("failed to unmarshal request data: %w", err))) - return - } - - // Call service method implementation. - err = s.Sessions.SaveWallet(ctx, reqPayload.Arg0, reqPayload.Arg1) - if err != nil { - rpcErr, ok := err.(WebRPCError) - if !ok { - rpcErr = ErrWebrpcEndpoint.WithCause(err) - } - s.sendErrorJSON(w, r, rpcErr) - return - } - - w.Header().Set("Content-Type", "application/json") - w.WriteHeader(http.StatusOK) - w.Write([]byte("{}")) -} - -func (s *sessionsServer) serveSaveSignatureJSON(ctx context.Context, w http.ResponseWriter, r *http.Request) { - ctx = context.WithValue(ctx, MethodNameCtxKey, "SaveSignature") - - reqBody, err := io.ReadAll(r.Body) - if err != nil { - s.sendErrorJSON(w, r, ErrWebrpcBadRequest.WithCause(fmt.Errorf("failed to read request data: %w", err))) - return - } - defer r.Body.Close() - - reqPayload := struct { - Arg0 string `json:"wallet"` - Arg1 string `json:"digest"` - Arg2 string `json:"chainID"` - Arg3 string `json:"signature"` - Arg4 *interface{} `json:"toConfig"` - }{} - if err := json.Unmarshal(reqBody, &reqPayload); err != nil { - s.sendErrorJSON(w, r, ErrWebrpcBadRequest.WithCause(fmt.Errorf("failed to unmarshal request data: %w", err))) - return - } - - // Call service method implementation. - err = s.Sessions.SaveSignature(ctx, reqPayload.Arg0, reqPayload.Arg1, reqPayload.Arg2, reqPayload.Arg3, reqPayload.Arg4) - if err != nil { - rpcErr, ok := err.(WebRPCError) - if !ok { - rpcErr = ErrWebrpcEndpoint.WithCause(err) - } - s.sendErrorJSON(w, r, rpcErr) - return - } - - w.Header().Set("Content-Type", "application/json") - w.WriteHeader(http.StatusOK) - w.Write([]byte("{}")) -} - -func (s *sessionsServer) serveSaveSignerSignaturesJSON(ctx context.Context, w http.ResponseWriter, r *http.Request) { - ctx = context.WithValue(ctx, MethodNameCtxKey, "SaveSignerSignatures") - - reqBody, err := io.ReadAll(r.Body) - if err != nil { - s.sendErrorJSON(w, r, ErrWebrpcBadRequest.WithCause(fmt.Errorf("failed to read request data: %w", err))) - return - } - defer r.Body.Close() - - reqPayload := struct { - Arg0 string `json:"wallet"` - Arg1 string `json:"digest"` - Arg2 string `json:"chainID"` - Arg3 []string `json:"signatures"` - Arg4 *interface{} `json:"toConfig"` - }{} - if err := json.Unmarshal(reqBody, &reqPayload); err != nil { - s.sendErrorJSON(w, r, ErrWebrpcBadRequest.WithCause(fmt.Errorf("failed to unmarshal request data: %w", err))) - return - } - - // Call service method implementation. - err = s.Sessions.SaveSignerSignatures(ctx, reqPayload.Arg0, reqPayload.Arg1, reqPayload.Arg2, reqPayload.Arg3, reqPayload.Arg4) - if err != nil { - rpcErr, ok := err.(WebRPCError) - if !ok { - rpcErr = ErrWebrpcEndpoint.WithCause(err) - } - s.sendErrorJSON(w, r, rpcErr) - return - } - - w.Header().Set("Content-Type", "application/json") - w.WriteHeader(http.StatusOK) - w.Write([]byte("{}")) -} - -func (s *sessionsServer) serveSaveMigrationJSON(ctx context.Context, w http.ResponseWriter, r *http.Request) { - ctx = context.WithValue(ctx, MethodNameCtxKey, "SaveMigration") - - reqBody, err := io.ReadAll(r.Body) - if err != nil { - s.sendErrorJSON(w, r, ErrWebrpcBadRequest.WithCause(fmt.Errorf("failed to read request data: %w", err))) - return - } - defer r.Body.Close() - - reqPayload := struct { - Arg0 string `json:"wallet"` - Arg1 int `json:"fromVersion"` - Arg2 int `json:"toVersion"` - Arg3 interface{} `json:"toConfig"` - Arg4 string `json:"executor"` - Arg5 []*Transaction `json:"transactions"` - Arg6 string `json:"nonce"` - Arg7 string `json:"signature"` - Arg8 *string `json:"chainID"` - }{} - if err := json.Unmarshal(reqBody, &reqPayload); err != nil { - s.sendErrorJSON(w, r, ErrWebrpcBadRequest.WithCause(fmt.Errorf("failed to unmarshal request data: %w", err))) - return - } - - // Call service method implementation. - err = s.Sessions.SaveMigration(ctx, reqPayload.Arg0, reqPayload.Arg1, reqPayload.Arg2, reqPayload.Arg3, reqPayload.Arg4, reqPayload.Arg5, reqPayload.Arg6, reqPayload.Arg7, reqPayload.Arg8) - if err != nil { - rpcErr, ok := err.(WebRPCError) - if !ok { - rpcErr = ErrWebrpcEndpoint.WithCause(err) - } - s.sendErrorJSON(w, r, rpcErr) - return - } - - w.Header().Set("Content-Type", "application/json") - w.WriteHeader(http.StatusOK) - w.Write([]byte("{}")) -} - -func (s *sessionsServer) sendErrorJSON(w http.ResponseWriter, r *http.Request, rpcErr WebRPCError) { - if s.OnError != nil { - s.OnError(r, &rpcErr) - } - - w.Header().Set("Content-Type", "application/json") - w.WriteHeader(rpcErr.HTTPStatus) - - respBody, _ := json.Marshal(rpcErr) - w.Write(respBody) -} - -func RespondWithError(w http.ResponseWriter, err error) { - rpcErr, ok := err.(WebRPCError) - if !ok { - rpcErr = ErrWebrpcEndpoint.WithCause(err) - } - - w.Header().Set("Content-Type", "application/json") - w.WriteHeader(rpcErr.HTTPStatus) - - respBody, _ := json.Marshal(rpcErr) - w.Write(respBody) -} - // // Client // @@ -745,12 +340,12 @@ const SessionsPathPrefix = "/rpc/Sessions/" type sessionsClient struct { client HTTPClient - urls [11]string + urls [12]string } func NewSessionsClient(addr string, client HTTPClient) SessionsClient { prefix := urlBase(addr) + SessionsPathPrefix - urls := [11]string{ + urls := [12]string{ prefix + "Ping", prefix + "Config", prefix + "Wallets", @@ -761,6 +356,7 @@ func NewSessionsClient(addr string, client HTTPClient) SessionsClient { prefix + "SaveWallet", prefix + "SaveSignature", prefix + "SaveSignerSignatures", + prefix + "SaveSignerSignatures2", prefix + "SaveMigration", } return &sessionsClient{ @@ -802,12 +398,15 @@ func (c *sessionsClient) Config(ctx context.Context, imageHash string) (int, int return out.Ret0, out.Ret1, err } -func (c *sessionsClient) Wallets(ctx context.Context, signer string) (map[string]*Signature, error) { +func (c *sessionsClient) Wallets(ctx context.Context, signer string, cursor *uint64, limit *uint64) (map[string]*Signature, uint64, error) { in := struct { - Arg0 string `json:"signer"` - }{signer} + Arg0 string `json:"signer"` + Arg1 *uint64 `json:"cursor"` + Arg2 *uint64 `json:"limit"` + }{signer, cursor, limit} out := struct { Ret0 map[string]*Signature `json:"wallets"` + Ret1 uint64 `json:"cursor"` }{} resp, err := doHTTPRequest(ctx, c.client, c.urls[2], in, &out) @@ -818,7 +417,7 @@ func (c *sessionsClient) Wallets(ctx context.Context, signer string) (map[string } } - return out.Ret0, err + return out.Ret0, out.Ret1, err } func (c *sessionsClient) DeployHash(ctx context.Context, wallet string) (string, *Context, error) { @@ -918,14 +517,15 @@ func (c *sessionsClient) SaveWallet(ctx context.Context, version int, deployConf return err } -func (c *sessionsClient) SaveSignature(ctx context.Context, wallet string, digest string, chainID string, signature string, toConfig *interface{}) error { +func (c *sessionsClient) SaveSignature(ctx context.Context, wallet string, digest string, chainID string, signature string, toConfig *interface{}, referenceChainID *string) error { in := struct { Arg0 string `json:"wallet"` Arg1 string `json:"digest"` Arg2 string `json:"chainID"` Arg3 string `json:"signature"` Arg4 *interface{} `json:"toConfig"` - }{wallet, digest, chainID, signature, toConfig} + Arg5 *string `json:"referenceChainID"` + }{wallet, digest, chainID, signature, toConfig, referenceChainID} resp, err := doHTTPRequest(ctx, c.client, c.urls[8], in, nil) if resp != nil { @@ -958,6 +558,26 @@ func (c *sessionsClient) SaveSignerSignatures(ctx context.Context, wallet string return err } +func (c *sessionsClient) SaveSignerSignatures2(ctx context.Context, wallet string, digest string, chainID string, signatures []*SignerSignature, toConfig *interface{}) error { + in := struct { + Arg0 string `json:"wallet"` + Arg1 string `json:"digest"` + Arg2 string `json:"chainID"` + Arg3 []*SignerSignature `json:"signatures"` + Arg4 *interface{} `json:"toConfig"` + }{wallet, digest, chainID, signatures, toConfig} + + resp, err := doHTTPRequest(ctx, c.client, c.urls[10], in, nil) + if resp != nil { + cerr := resp.Body.Close() + if err == nil && cerr != nil { + err = ErrWebrpcRequestFailed.WithCause(fmt.Errorf("failed to close response body: %w", cerr)) + } + } + + return err +} + func (c *sessionsClient) SaveMigration(ctx context.Context, wallet string, fromVersion int, toVersion int, toConfig interface{}, executor string, transactions []*Transaction, nonce string, signature string, chainID *string) error { in := struct { Arg0 string `json:"wallet"` @@ -971,7 +591,7 @@ func (c *sessionsClient) SaveMigration(ctx context.Context, wallet string, fromV Arg8 *string `json:"chainID"` }{wallet, fromVersion, toVersion, toConfig, executor, transactions, nonce, signature, chainID} - resp, err := doHTTPRequest(ctx, c.client, c.urls[10], in, nil) + resp, err := doHTTPRequest(ctx, c.client, c.urls[11], in, nil) if resp != nil { cerr := resp.Body.Close() if err == nil && cerr != nil { @@ -1103,6 +723,12 @@ func HTTPRequestHeaders(ctx context.Context) (http.Header, bool) { // Helpers // +type method struct { + Name string + Service string + Annotations map[string]string +} + type contextKey struct { name string } @@ -1113,9 +739,7 @@ func (k *contextKey) String() string { var ( HTTPClientRequestHeadersCtxKey = &contextKey{"HTTPClientRequestHeaders"} - HTTPResponseWriterCtxKey = &contextKey{"HTTPResponseWriter"} - - HTTPRequestCtxKey = &contextKey{"HTTPRequest"} + HTTPRequestCtxKey = &contextKey{"HTTPRequest"} ServiceNameCtxKey = &contextKey{"ServiceName"} @@ -1136,9 +760,19 @@ func RequestFromContext(ctx context.Context) *http.Request { r, _ := ctx.Value(HTTPRequestCtxKey).(*http.Request) return r } -func ResponseWriterFromContext(ctx context.Context) http.ResponseWriter { - w, _ := ctx.Value(HTTPResponseWriterCtxKey).(http.ResponseWriter) - return w + +func MethodCtx(ctx context.Context) (method, bool) { + req := RequestFromContext(ctx) + if req == nil { + return method{}, false + } + + m, ok := methods[req.URL.Path] + if !ok { + return method{}, false + } + + return m, true } // @@ -1215,5 +849,5 @@ var ( // Schema errors var ( ErrInvalidArgument = WebRPCError{Code: 1, Name: "InvalidArgument", Message: "invalid argument", HTTPStatus: 400} - ErrNotFound = WebRPCError{Code: 2, Name: "NotFound", Message: "not found", HTTPStatus: 404} + ErrNotFound = WebRPCError{Code: 2, Name: "NotFound", Message: "not found", HTTPStatus: 400} )