This is an automated email from the ASF dual-hosted git repository.

colegreer pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/tinkerpop.git

commit 2553564678a2e6a4223dc09fc645d23c5f7b2d1b
Merge: cad9022e76 8aad40518b
Author: Cole Greer <[email protected]>
AuthorDate: Mon Jan 12 13:11:08 2026 -0800

    Merge branch '3.8-dev'

 CHANGELOG.asciidoc                               |  5 +-
 gremlin-examples/gremlin-go/basic_gremlin.go     | 17 +++---
 gremlin-examples/gremlin-go/connections.go       | 31 +++++-----
 gremlin-examples/gremlin-go/modern_traversals.go |  3 +-
 gremlin-go/docker-compose.yml                    |  8 ++-
 gremlin-go/driver/client.go                      |  4 +-
 gremlin-go/driver/request.go                     | 44 +++++++++++++-
 gremlin-go/driver/request_test.go                |  8 +--
 gremlin-go/driver/response.go                    | 20 +++----
 gremlin-go/driver/resultSet.go                   | 45 ++++++++++++++
 gremlin-go/driver/serializer.go                  | 76 ++++++++++++++++++------
 gremlin-go/driver/serializer_test.go             | 28 ++++-----
 gremlin-go/examples/basic_gremlin.go             | 23 +++++--
 gremlin-go/examples/connections.go               | 29 +++++----
 gremlin-go/examples/modern_traversals.go         | 14 ++++-
 15 files changed, 261 insertions(+), 94 deletions(-)

diff --cc CHANGELOG.asciidoc
index 64eb99ab8d,27c1e7673e..2db6f4de28
--- a/CHANGELOG.asciidoc
+++ b/CHANGELOG.asciidoc
@@@ -14,75 -14,7 +14,76 @@@ WITHOUT WARRANTIES OR CONDITIONS OF AN
  See the License for the specific language governing permissions and
  limitations under the License.
  ////
 -= TinkerPop3 CHANGELOG
 += TinkerPop CHANGELOG
 +
 +== TinkerPop 4.0.0 (Gremlin's Wildest Dreams)
 +
 
+image::https://raw.githubusercontent.com/apache/tinkerpop/master/docs/static/images/gremlins-wildest-dreams.png[width=185]
 +
 +[[release-4-0-0]]
 +=== TinkerPop 4.0.0 (NOT OFFICIALLY RELEASED YET)
 +
 +* Bumped SLF4j to 2.0.16.
 +* Modified grammar to make `discard()` usage more consistent as a filter step 
where it can now be used to chain additional traversal steps and be used 
anonymously.
 +* Bumped GMavenPlus to 4.1.1
++* Removed `Meta` field from `ResponseResult` struct in `gremlin-go`
 +
 +[[release-4-0-0-beta-1]]
 +=== TinkerPop 4.0.0-beta.1 (January 17, 2025)
 +
 +* Added support for deserialization of `Set` for `gremlin-javascript`.
 +* Added grammar-based `Translator` for all languages including explicit ones 
for Java and anonymization.
 +* Removed old `Translator` infrastructure.
 +* Removed grammar support for enums to be used as variables.
 +* Changed `valueMap` in grammar to disallow the `boolean` argument as a 
variable to avoid ambiguous step calls.
 +* Added integer overflow checks for `sum()`.
 +* Modified Gremlin Server to only support instantiation of 
`authentication.authenticationHandler` with three-arg constructor.
 +* Removed previously deprecated two-arg constructors for 
`authentication.authenticationHandler` implementations.
 +* Removed previously deprecated one-arg constructor for 
`AbstractAuthenticationHandler`.
 +* Renamed the traversal discarding `none()` step to `discard()`.
 +* Added new list filtering step `none()`.
 +* Replaced `gremlin-groovy` with `gremlin-lang` as the default language in 
`gremlin-server`.
 +* Changed `sum()` to retain the type common to the stream rather than always 
promoting to `long` given the need for it to multiple by the `long` bulk value 
for the traverser.
 +* Added support for `Set` in GraphSON and GraphBinary serialization for 
`gremlin-javascript`, where it previously just converted to array.
 +* Added `Set` syntax in `gremlin-language`.
 +* Modified RequestInterceptor to be a `UnaryOperator<HttpRequest>` to 
abstract the underlying implementation.
 +* Removed the `gremlin-archetype` module in favor of newer sample 
applications in each GLV's `examples` folder.
 +* Bumped to `commons-collection4`.
 +* Switched to HTTP protocol in `gremlin-python` and replaced GraphSONV2, 
GraphSONV2 & GraphBinaryV1 with GraphBinaryV4
 +* Added support for chunked transfer in `gremlin-python`
 +* Added TypeScript & ECMAScript module support.
 +* Improved graph structures type definitions in TypeScript.
 +* Removed usage of `Bytecode` for Gremlin Server and Java GLV, script engines 
and `GremlinExecutor` will not be able to handle `Bytecode`.
 +* Removed `Bytecode` based authorization.
 +* Added `GremlinLang` which allows to generate gremlin-lang compatible string 
based on Traversal.
 +* Removed serialization support for `Bindings` and `Bytecode`.
 +* Changed `EmbeddedRemoteConnection` to prefer the grammar-based translator.
 +* Removed `Client.submit(Traversal)` as a mechanism for submitting traversal, 
prefer `DriverRemoteConnection` instead.
 +* Removed usage of `Bytecode` from `gremlin-python`.
 +* Added `auth` module in `gremlin-python` for pluggable authentication.
 +* Fixed `GremlinLangScriptEngine` handling for some strategies.
 +* Updated Docker test suite set-up in `gremlin-python` to work with HTTP 
driver/server.
 +* Updated `DateTime` serializers for Java and Python according to 
GraphBinaryV4.
 +* Defined GraphBinaryV4 specification.
 +* Defined GraphSONV4 specification.
 +* Update serializers for `label` of an `Element` as a singleton list of 
string for GraphBinaryV4.
 +* Added `bulked` byte to `Response Message` serialization for GraphBinaryV4.
 +* Added a `bulked` header set by cluster setting, as well as a with `bulked` 
request option to turn on the bulking of result data.
 +* Updated `List` and `BulkSet` serializers to implement `bulk` value flag for 
`List`.
 +* Renamed `maxContentLength` setting for Gremlin Driver to 
`maxResponseContentLength` and blocked incoming responses that are too large 
based on total response size.
 +* Renamed `maxContentLength` setting for Gremlin Server to 
`maxRequestContentLength`.
 +* Added missing strategies to the `TraversalStrategies` global cache as well 
as `CoreImports` in `gremlin-groovy`.
 +* Added missing strategies to `strategies.py` in `gremlin-python`.
 +* Updated `OptionsStrategy` in `gremlin-python` to take options directly as 
keyword arguments.
 +* Added static `instance()` method to `ElementIdStrategy` to an instance with 
the default configuration.
 +* Updated `ElementIdStrategy.getConfiguration()` to help with serialization.
 +* Updated `TraversalStrategyProxy` to utilize strategy names instead of 
strategy classes
 +* Established mechanism for using customer strategies in remote context by 
using `TraversalStrategyProxy` in Java, or `TraversalStrategy` in GLVs.
 +* Removed `minSize` setting for Gremlin Driver connection pool since 
connections are now short-lived HTTP connections
 +* Added `idleConnectionTimeout` setting for Gremlin Driver and automatic 
closing of idle connections
 +* Enabled TCP Keep-Alive in GremlinServer.
 +* Updated Python GLV examples to use HTTP and to run as part of the 
integration tests.
 +* Fixed `gremlin-python` `to()` and `from_()` methods to wrap Vertex objects 
with `__.V()` for proper edge creation.
  
  == TinkerPop 3.8.0 (Grix Greven)
  
diff --cc gremlin-go/docker-compose.yml
index c4de751ec0,c499e94d04..733277fecd
--- a/gremlin-go/docker-compose.yml
+++ b/gremlin-go/docker-compose.yml
@@@ -55,6 -58,9 +55,7 @@@ services
        - RUN_INTEGRATION_TESTS=true
        - RUN_INTEGRATION_WITH_ALIAS_TESTS=true
        - RUN_BASIC_AUTH_INTEGRATION_TESTS=true
 -      - GREMLIN_SOCKET_SERVER_URL=ws://gremlin-socket-server-go
 -      - 
GREMLIN_SOCKET_SERVER_CONFIG_PATH=/go_app/gremlin-socket-server/conf/test-ws-gremlin.yaml
+       - VERTEX_LABEL=go-example
      working_dir: /go_app
      command: >
        bash -c "go install 
github.com/gotesttools/gotestfmt/v2/cmd/gotestfmt@latest
diff --cc gremlin-go/driver/client.go
index ff625f6dff,705330192f..f5646985e7
--- a/gremlin-go/driver/client.go
+++ b/gremlin-go/driver/client.go
@@@ -127,12 -149,12 +127,12 @@@ func (client *Client) Close() 
  // SubmitWithOptions submits a Gremlin script to the server with specified 
RequestOptions and returns a ResultSet.
  func (client *Client) SubmitWithOptions(traversalString string, 
requestOptions RequestOptions) (ResultSet, error) {
        client.logHandler.logf(Debug, submitStartedString, traversalString)
-       request := makeStringRequest(traversalString, client.traversalSource, 
requestOptions)
 -      request := MakeStringRequest(traversalString, client.traversalSource, 
client.session, requestOptions)
 -      result, err := client.connections.write(&request)
 -      if err != nil {
 -              client.logHandler.logf(Error, logErrorGeneric, 
"Client.Submit()", err.Error())
 -      }
 -      return result, err
++      request := MakeStringRequest(traversalString, client.traversalSource, 
requestOptions)
 +
 +      // TODO interceptors (ie. auth)
 +
 +      rs, err := client.gremlinClient.send(&request)
 +      return rs, err
  }
  
  // Submit submits a Gremlin script to the server and returns a ResultSet. 
Submit can optionally accept a map of bindings
@@@ -149,6 -171,16 +149,6 @@@ func (client *Client) Submit(traversalS
  // submitBytecode submits Bytecode to the server to execute and returns a 
ResultSet.
  func (client *Client) submitBytecode(bytecode *Bytecode) (ResultSet, error) {
        client.logHandler.logf(Debug, submitStartedBytecode, *bytecode)
-       request := makeBytecodeRequest(bytecode, client.traversalSource)
 -      request := MakeBytecodeRequest(bytecode, client.traversalSource, 
client.session)
 -      return client.connections.write(&request)
 -}
 -
 -func (client *Client) closeSession() error {
 -      message := makeCloseSessionRequest(client.session)
 -      result, err := client.connections.write(&message)
 -      if err != nil {
 -              return err
 -      }
 -      _, err = result.All()
 -      return err
++      request := MakeBytecodeRequest(bytecode, client.traversalSource)
 +      return client.gremlinClient.send(&request)
  }
diff --cc gremlin-go/driver/request.go
index 79581b959e,436a8a39fd..b5eebe65d3
--- a/gremlin-go/driver/request.go
+++ b/gremlin-go/driver/request.go
@@@ -19,16 -19,61 +19,36 @@@ under the License
  
  package gremlingo
  
 -import (
 -      "github.com/google/uuid"
 -)
 -
  // request represents a request to the server.
  type request struct {
 -      requestID uuid.UUID
 -      op        string
 -      processor string
 -      args      map[string]interface{}
 +      gremlin string
 +      fields  map[string]interface{}
  }
  
- func makeStringRequest(stringGremlin string, traversalSource string, 
requestOptions RequestOptions) (req request) {
 -const sessionProcessor = "session"
 -
 -const stringOp = "eval"
 -const stringProcessor = ""
 -
+ // MakeStringRequest creates a request from a Gremlin string query for 
submission to a Gremlin server.
+ //
+ // This function is exposed publicly to enable alternative transport 
protocols (gRPC, HTTP/2, etc.)
+ // to construct properly formatted requests outside the standard WebSocket 
client. The returned
+ // request can then be serialized using SerializeMessage().
+ //
+ // Parameters:
+ //   - stringGremlin: The Gremlin query string to execute
+ //   - traversalSource: The name of the traversal source (typically "g")
 -//   - sessionId: Optional session ID for stateful requests (use "" for 
stateless)
+ //   - requestOptions: Options such as bindings, timeout, batch size, etc.
+ //
+ // Returns:
+ //   - request: A request structure ready for serialization
+ //
+ // Example for alternative transports:
+ //
 -//    req := MakeStringRequest("g.V().count()", "g", "", RequestOptions{})
++//    req := MakeStringRequest("g.V().count()", "g", RequestOptions{})
+ //    serializer := newGraphBinarySerializer(nil)
+ //    bytes, _ := serializer.(graphBinarySerializer).SerializeMessage(&req)
+ //    // Send bytes over gRPC, HTTP/2, etc.
 -func MakeStringRequest(stringGremlin string, traversalSource string, 
sessionId string, requestOptions RequestOptions) (req request) {
 -      newProcessor := stringProcessor
 -      newArgs := map[string]interface{}{
 -              "gremlin": stringGremlin,
 -              "aliases": map[string]interface{}{
 -                      "g": traversalSource,
 -              },
 -      }
 -      if sessionId != "" {
 -              newProcessor = sessionProcessor
 -              newArgs["session"] = sessionId
 -      }
 -      var requestId uuid.UUID
 -      if requestOptions.requestID == uuid.Nil {
 -              requestId = uuid.New()
 -      } else {
 -              requestId = requestOptions.requestID
++func MakeStringRequest(stringGremlin string, traversalSource string, 
requestOptions RequestOptions) (req request) {
 +      newFields := map[string]interface{}{
 +              "language": "gremlin-lang",
 +              "g":        traversalSource,
        }
  
        if requestOptions.bindings != nil {
@@@ -57,8 -104,35 +77,28 @@@
        }
  }
  
- func makeBytecodeRequest(bytecodeGremlin *Bytecode, traversalSource string) 
(req request) {
 -const bytecodeOp = "bytecode"
 -const bytecodeProcessor = "traversal"
 -const authOp = "authentication"
 -const authProcessor = "traversal"
 -
+ // MakeBytecodeRequest creates a request from Gremlin bytecode for submission 
to a Gremlin server.
+ //
+ // This function is exposed publicly to enable alternative transport 
protocols (gRPC, HTTP/2, etc.)
+ // to construct properly formatted requests outside the standard WebSocket 
client. The returned
+ // request can then be serialized using SerializeMessage().
+ //
+ // Parameters:
+ //   - bytecodeGremlin: The Gremlin bytecode to execute
+ //   - traversalSource: The name of the traversal source (typically "g")
 -//   - sessionId: Optional session ID for stateful requests (use "" for 
stateless)
+ //
+ // Returns:
+ //   - request: A request structure ready for serialization
+ //
+ // Example for alternative transports:
+ //
+ //    bytecode := g.V().HasLabel("person").Bytecode
 -//    req := MakeBytecodeRequest(bytecode, "g", "")
++//    req := MakeBytecodeRequest(bytecode, "g")
+ //    serializer := newGraphBinarySerializer(nil)
+ //    bytes, _ := serializer.(graphBinarySerializer).SerializeMessage(&req)
+ //    // Send bytes over gRPC, HTTP/2, etc.
 -func MakeBytecodeRequest(bytecodeGremlin *Bytecode, traversalSource string, 
sessionId string) (req request) {
 -      newProcessor := bytecodeProcessor
 -      newArgs := map[string]interface{}{
++func MakeBytecodeRequest(bytecodeGremlin *Bytecode, traversalSource string) 
(req request) {
 +      newFields := map[string]interface{}{
                "gremlin": *bytecodeGremlin,
                "aliases": map[string]interface{}{
                        "g": traversalSource,
diff --cc gremlin-go/driver/request_test.go
index d6d4b03268,e20a5a06de..c88ef32f69
--- a/gremlin-go/driver/request_test.go
+++ b/gremlin-go/driver/request_test.go
@@@ -26,29 -28,40 +26,29 @@@ import 
  )
  
  func TestRequest(t *testing.T) {
 -      t.Run("Test makeStringRequest() with custom requestID", func(t 
*testing.T) {
 -              requestId := uuid.New()
 -              r := MakeStringRequest("g.V()", "g", "",
 -                      
new(RequestOptionsBuilder).SetRequestId(requestId).Create())
 -              assert.Equal(t, requestId, r.requestID)
 -      })
 -
        t.Run("Test makeStringRequest() with no bindings", func(t *testing.T) {
-               r := makeStringRequest("g.V()", "g", *new(RequestOptions))
 -              r := MakeStringRequest("g.V()", "g", "", *new(RequestOptions))
 -              assert.NotNil(t, r.requestID)
 -              assert.NotEqual(t, uuid.Nil, r.requestID)
++              r := MakeStringRequest("g.V()", "g", *new(RequestOptions))
 +              assert.Equal(t, "g.V()", r.gremlin)
 +              assert.Equal(t, "g", r.fields["g"])
 +              assert.Equal(t, "gremlin-lang", r.fields["language"])
 +              assert.Nil(t, r.fields["bindings"])
        })
  
        t.Run("Test makeStringRequest() with custom evaluationTimeout", func(t 
*testing.T) {
-               r := makeStringRequest("g.V()", "g",
 -              r := MakeStringRequest("g.V()", "g", "",
++              r := MakeStringRequest("g.V()", "g",
                        
new(RequestOptionsBuilder).SetEvaluationTimeout(1234).Create())
 -              assert.NotNil(t, r.requestID)
 -              assert.NotEqual(t, uuid.Nil, r.requestID)
 -              assert.Equal(t, 1234, r.args["evaluationTimeout"])
 +              assert.Equal(t, 1234, r.fields["evaluationTimeout"])
        })
  
        t.Run("Test makeStringRequest() with custom batchSize", func(t 
*testing.T) {
-               r := makeStringRequest("g.V()", "g",
 -              r := MakeStringRequest("g.V()", "g", "",
++              r := MakeStringRequest("g.V()", "g",
                        new(RequestOptionsBuilder).SetBatchSize(123).Create())
 -              assert.NotNil(t, r.requestID)
 -              assert.NotEqual(t, uuid.Nil, r.requestID)
 -              assert.Equal(t, 123, r.args["batchSize"])
 +              assert.Equal(t, 123, r.fields["batchSize"])
        })
  
        t.Run("Test makeStringRequest() with custom userAgent", func(t 
*testing.T) {
-               r := makeStringRequest("g.V()", "g",
 -              r := MakeStringRequest("g.V()", "g", "",
++              r := MakeStringRequest("g.V()", "g",
                        
new(RequestOptionsBuilder).SetUserAgent("TestUserAgent").Create())
 -              assert.NotNil(t, r.requestID)
 -              assert.NotEqual(t, uuid.Nil, r.requestID)
 -              assert.Equal(t, "TestUserAgent", r.args["userAgent"])
 +              assert.Equal(t, "TestUserAgent", r.fields["userAgent"])
        })
  }
diff --cc gremlin-go/driver/response.go
index dfe89ac07f,6eadf351b5..c2a08d550a
--- a/gremlin-go/driver/response.go
+++ b/gremlin-go/driver/response.go
@@@ -21,21 -21,22 +21,21 @@@ package gremling
  
  import "github.com/google/uuid"
  
- // responseStatus contains the status info of the response.
- type responseStatus struct {
+ // ResponseStatus contains the status info of the response.
+ type ResponseStatus struct {
 -      code       uint16
 -      message    string
 -      attributes map[string]interface{}
 +      code      uint32
 +      message   string
 +      exception string
  }
  
- // responseResult contains the result info of the response.
- type responseResult struct {
-       data interface{}
+ // ResponseResult contains the result info of the response.
+ type ResponseResult struct {
 -      Meta map[string]interface{}
+       Data interface{}
  }
  
- // response represents a response from the server.
- type response struct {
-       responseID     uuid.UUID
-       responseStatus responseStatus
-       responseResult responseResult
+ // Response represents a Response from the server.
+ type Response struct {
+       ResponseID     uuid.UUID
+       ResponseStatus ResponseStatus
+       ResponseResult ResponseResult
  }
diff --cc gremlin-go/driver/resultSet.go
index 8079744bd3,6472880b77..59e22e66d1
--- a/gremlin-go/driver/resultSet.go
+++ b/gremlin-go/driver/resultSet.go
@@@ -169,10 -204,56 +169,55 @@@ func (channelResultSet *channelResultSe
        channelResultSet.sendSignal()
  }
  
 -func newChannelResultSetCapacity(requestID string, container 
*synchronizedMap, channelSize int) ResultSet {
 -      return &channelResultSet{make(chan *Result, channelSize), requestID, 
container, "", nil, false, nil, nil, sync.Mutex{}, sync.Mutex{}}
 +func newChannelResultSetCapacity(channelSize int) ResultSet {
 +      return &channelResultSet{make(chan *Result, channelSize), "", false, 
nil, nil, sync.Mutex{}, sync.Mutex{}}
  }
  
 -func newChannelResultSet(requestID string, container *synchronizedMap) 
ResultSet {
 -      return newChannelResultSetCapacity(requestID, container, 
defaultCapacity)
 +func newChannelResultSet() ResultSet {
 +      return newChannelResultSetCapacity(defaultCapacity)
  }
+ 
+ // NewResultSet creates a new ResultSet from a slice of Result objects.
+ // This function enables custom transport implementations to create 
ResultSets from
+ // results collected via alternative protocols.
+ //
+ // The function creates a channel-based ResultSet, pre-populates it with the 
provided results,
+ // and closes the channel to indicate completion.
+ //
+ // Parameters:
 -//   - requestID: The request identifier for this ResultSet
+ //   - results: A slice of Result objects to include in the ResultSet
+ //
+ // Returns:
+ //   - ResultSet: A ResultSet containing all the provided results
+ //
+ // Example usage:
+ //
+ //    var results []*Result
+ //    // Collect results from custom transport
+ //    for _, responseBytes := range responses {
+ //        result, _ := DeserializeResult(responseBytes)
+ //        results = append(results, result)
+ //    }
+ //    resultSet := NewResultSet("request-123", results)
+ //    allResults, _ := resultSet.All()
 -func NewResultSet(requestID string, results []*Result) ResultSet {
++func NewResultSet(results []*Result) ResultSet {
+       // Create a channel-based result set with capacity for all results
+       channelSize := len(results)
+       if channelSize == 0 {
+               channelSize = 1 // Ensure at least size 1
+       }
 -      rs := newChannelResultSetCapacity(requestID, 
&synchronizedMap{make(map[string]ResultSet), sync.Mutex{}}, 
channelSize).(*channelResultSet)
++      rs := newChannelResultSetCapacity(channelSize).(*channelResultSet)
+ 
+       // Add all results to the channel
+       for _, result := range results {
+               rs.channel <- result
+       }
+ 
+       // Close the channel to indicate no more results
+       rs.channelMutex.Lock()
+       rs.closed = true
+       close(rs.channel)
+       rs.channelMutex.Unlock()
+ 
+       return rs
+ }
diff --cc gremlin-go/driver/serializer.go
index 7ef810ab53,28f1c0ff07..efd32618f1
--- a/gremlin-go/driver/serializer.go
+++ b/gremlin-go/driver/serializer.go
@@@ -22,19 -22,24 +22,19 @@@ package gremling
  import (
        "bytes"
        "encoding/binary"
 -      "math/big"
 -      "reflect"
 -      "strings"
        "sync"
 -
 -      "github.com/google/uuid"
  )
  
 -const graphBinaryMimeType = "application/vnd.graphbinary-v1.0"
 +const graphBinaryMimeType = "application/vnd.graphbinary-v4.0"
  
- // serializer interface for serializers.
- type serializer interface {
-       serializeMessage(request *request) ([]byte, error)
-       deserializeMessage(message []byte) (response, error)
+ // Serializer interface for serializers.
+ type Serializer interface {
+       SerializeMessage(request *request) ([]byte, error)
+       DeserializeMessage(message []byte) (Response, error)
  }
  
- // graphBinarySerializer serializes/deserializes message to/from GraphBinary.
- type graphBinarySerializer struct {
+ // GraphBinarySerializer serializes/deserializes message to/from GraphBinary.
+ type GraphBinarySerializer struct {
        ser *graphBinaryTypeSerializer
  }
  
@@@ -63,18 -68,73 +63,40 @@@ func newGraphBinarySerializer(handler *
  
  const versionByte byte = 0x81
  
 -func convertArgs(request *request, gs GraphBinarySerializer) 
(map[string]interface{}, error) {
 -      if request.op != bytecodeProcessor {
 -              return request.args, nil
 -      }
 -
 -      // Convert to format:
 -      // args["gremlin"]: <serialized args["gremlin"]>
 -      gremlin := request.args["gremlin"]
 -      switch gremlin.(type) {
 -      case Bytecode:
 -              buffer := bytes.Buffer{}
 -              gremlinBuffer, err := gs.ser.write(gremlin, &buffer)
 -              if err != nil {
 -                      return nil, err
 -              }
 -              request.args["gremlin"] = gremlinBuffer
 -              return request.args, nil
 -      default:
 -              var typeName string
 -              if gremlin != nil {
 -                      typeName = reflect.TypeOf(gremlin).Name()
 -              }
 -
 -              return nil, newError(err0704ConvertArgsNoSerializerError, 
typeName)
 -      }
 -}
 -
+ // SerializeMessage serializes a request message into GraphBinary format.
+ //
+ // This method is part of the serializer interface and is used internally by 
the WebSocket driver.
+ // It is also exposed publicly to enable alternative transport protocols 
(gRPC, HTTP/2, etc.) to
+ // serialize requests created with MakeBytecodeRequest() or 
MakeStringRequest().
+ //
+ // The serialized bytes can be transmitted over any transport protocol that 
supports binary data.
+ //
+ // Parameters:
+ //   - request: The request to serialize (created via MakeBytecodeRequest or 
MakeStringRequest)
+ //
+ // Returns:
+ //   - []byte: The GraphBinary-encoded request ready for transmission
+ //   - error: Any serialization error encountered
+ //
+ // Example for alternative transports:
+ //
+ //    req := MakeBytecodeRequest(bytecode, "g", "")
+ //    serializer := newGraphBinarySerializer(nil)
+ //    bytes, err := serializer.(graphBinarySerializer).SerializeMessage(&req)
+ //    // Send bytes over custom transport
++//
 +// serializeMessage serializes a request message into GraphBinary.
- func (gs graphBinarySerializer) serializeMessage(request *request) ([]byte, 
error) {
+ func (gs GraphBinarySerializer) SerializeMessage(request *request) ([]byte, 
error) {
 -      args, err := convertArgs(request, gs)
 -      if err != nil {
 -              return nil, err
 -      }
 -      finalMessage, err := gs.buildMessage(request.requestID, 
byte(len(graphBinaryMimeType)), request.op, request.processor, args)
 +      finalMessage, err := gs.buildMessage(request.gremlin, request.fields)
        if err != nil {
                return nil, err
        }
        return finalMessage, nil
  }
  
- func (gs *graphBinarySerializer) buildMessage(gremlin string, args 
map[string]interface{}) ([]byte, error) {
 -func (gs *GraphBinarySerializer) buildMessage(id uuid.UUID, mimeLen byte, op 
string, processor string, args map[string]interface{}) ([]byte, error) {
++func (gs *GraphBinarySerializer) buildMessage(gremlin string, args 
map[string]interface{}) ([]byte, error) {
        buffer := bytes.Buffer{}
  
 -      // mime header
 -      buffer.WriteByte(mimeLen)
 -      buffer.WriteString(graphBinaryMimeType)
 -
        // Version
        buffer.WriteByte(versionByte)
  
@@@ -90,9 -172,59 +112,27 @@@
        return buffer.Bytes(), nil
  }
  
- // deserializeMessage deserializes a response message.
- func (gs graphBinarySerializer) deserializeMessage(message []byte) (response, 
error) {
-       var msg response
 -func uuidToBigInt(requestID uuid.UUID) big.Int {
 -      var bigInt big.Int
 -      bigInt.SetString(strings.Replace(requestID.String(), "-", "", 4), 16)
 -      return bigInt
 -}
 -
+ // DeserializeMessage deserializes a GraphBinary-encoded response message.
+ //
+ // This method is part of the serializer interface and is used internally by 
the WebSocket driver.
+ // It is also exposed publicly to enable alternative transport protocols 
(gRPC, HTTP/2, etc.) to
+ // deserialize responses received from a Gremlin server.
+ //
+ // Parameters:
+ //   - message: The GraphBinary-encoded response bytes
+ //
+ // Returns:
 -//   - response: The deserialized response containing results and metadata
++//   - response: The deserialized Response containing results and metadata
+ //   - error: Any deserialization error encountered
+ //
+ // Example for alternative transports:
+ //
+ //    // Receive bytes from custom transport
+ //    serializer := newGraphBinarySerializer(nil)
+ //    resp, err := 
serializer.(graphBinarySerializer).DeserializeMessage(responseBytes)
+ //    results := resp.responseResult.data
+ func (gs GraphBinarySerializer) DeserializeMessage(message []byte) (Response, 
error) {
+       var msg Response
  
        if message == nil || len(message) == 0 {
                gs.ser.logHandler.log(Error, nullInput)
@@@ -108,30 -245,22 +148,30 @@@
                if err != nil {
                        return msg, err
                }
 -              msg.ResponseStatus.message = message.(string)
 +              results = append(results, n)
        }
 -      attr, err := readMapUnqualified(&message, &i)
 -      if err != nil {
 -              return msg, err
 +      if len(results) == 1 {
 +              // unwrap single results
-               msg.responseResult.data = results[0]
++              msg.ResponseResult.Data = results[0]
 +      } else {
-               msg.responseResult.data = results
++              msg.ResponseResult.Data = results
        }
 -      msg.ResponseStatus.attributes = attr.(map[string]interface{})
 -      meta, err := readMapUnqualified(&message, &i)
 +      code := readUint32Safe(&message, &i)
-       msg.responseStatus.code = code
++      msg.ResponseStatus.code = code
 +      statusMsg, err := readUnqualified(&message, &i, stringType, true)
        if err != nil {
                return msg, err
        }
 -      msg.ResponseResult.Meta = meta.(map[string]interface{})
 -      msg.ResponseResult.Data, err = readFullyQualifiedNullable(&message, &i, 
true)
 +      if statusMsg != nil {
-               msg.responseStatus.message = statusMsg.(string)
++              msg.ResponseStatus.message = statusMsg.(string)
 +      }
 +      exception, err := readUnqualified(&message, &i, stringType, true)
        if err != nil {
                return msg, err
        }
 +      if exception != nil {
-               msg.responseStatus.exception = exception.(string)
++              msg.ResponseStatus.exception = exception.(string)
 +      }
        return msg, nil
  }
  
diff --cc gremlin-go/driver/serializer_test.go
index 8bd16032f9,b8689da16b..756f0af15f
--- a/gremlin-go/driver/serializer_test.go
+++ b/gremlin-go/driver/serializer_test.go
@@@ -33,12 -34,15 +33,12 @@@ const mapDataOrder2 = "[32 97 112 112 1
  
  func TestSerializer(t *testing.T) {
        t.Run("test serialized request message", func(t *testing.T) {
 -              var u, _ = uuid.Parse("41d2e28a-20a4-4ab0-b379-d810dede3786")
                testRequest := request{
 -                      requestID: u,
 -                      op:        "eval",
 -                      processor: "",
 -                      args:      map[string]interface{}{"gremlin": 
"g.V().count()", "aliases": map[string]interface{}{"g": "g"}},
 +                      gremlin: "g.V().count()",
-                       fields: map[string]interface{}{"aliases": 
map[string]interface{}{"g": "g"}},
++                      fields:  map[string]interface{}{"aliases": 
map[string]interface{}{"g": "g"}},
                }
                serializer := 
newGraphBinarySerializer(newLogHandler(&defaultLogger{}, Error, 
language.English))
-               serialized, _ := serializer.serializeMessage(&testRequest)
+               serialized, _ := serializer.SerializeMessage(&testRequest)
                stringified := fmt.Sprintf("%v", serialized)
                if stringified != mapDataOrder1 && stringified != mapDataOrder2 
{
                        assert.Fail(t, "Error, expected serialized map data to 
match one of the provided binary arrays. Can vary based on ordering of keyset, 
but must map to one of two.")
@@@ -48,12 -52,14 +48,12 @@@
        t.Run("test serialized response message", func(t *testing.T) {
                responseByteArray := []byte{129, 0, 251, 37, 42, 74, 117, 221, 
71, 191, 183, 78, 86, 53, 0, 12, 132, 100, 0, 0, 0, 200, 0, 0, 0, 0, 0, 0, 0, 
0, 1, 3, 0, 0, 0, 0, 4, 104, 111, 115, 116, 3, 0, 0, 0, 0, 16, 47, 49, 50, 55, 
46, 48, 46, 48, 46, 49, 58, 54, 50, 48, 51, 53, 0, 0, 0, 0, 9, 0, 0, 0, 0, 1, 
2, 0, 0, 0, 0, 0, 0, 0, 0, 0}
                serializer := 
newGraphBinarySerializer(newLogHandler(&defaultLogger{}, Error, 
language.English))
-               response, err := 
serializer.deserializeMessage(responseByteArray)
+               response, err := 
serializer.DeserializeMessage(responseByteArray)
                assert.Nil(t, err)
-               assert.Equal(t, "fb252a4a-75dd-47bf-b74e-5635000c8464", 
response.responseID.String())
-               assert.Equal(t, uint16(200), response.responseStatus.code)
-               assert.Equal(t, "", response.responseStatus.message)
-               assert.Equal(t, []interface{}{int64(0)}, 
response.responseResult.data)
+               assert.Equal(t, "fb252a4a-75dd-47bf-b74e-5635000c8464", 
response.ResponseID.String())
+               assert.Equal(t, uint16(200), response.ResponseStatus.code)
+               assert.Equal(t, "", response.ResponseStatus.message)
 -              assert.Equal(t, map[string]interface{}{"host": 
"/127.0.0.1:62035"}, response.ResponseStatus.attributes)
 -              assert.Equal(t, map[string]interface{}{}, 
response.ResponseResult.Meta)
+               assert.Equal(t, []interface{}{int64(0)}, 
response.ResponseResult.Data)
        })
  
        t.Run("test serialized response message w/ custom type", func(t 
*testing.T) {
@@@ -63,23 -69,29 +63,23 @@@
                }()
                responseByteArray := []byte{129, 0, 69, 222, 40, 55, 95, 62, 
75, 249, 134, 133, 155, 133, 43, 151, 221, 68, 0, 0, 0, 200, 0, 0, 0, 0, 0, 0, 
0, 0, 1, 3, 0, 0, 0, 0, 4, 104, 111, 115, 116, 3, 0, 0, 0, 0, 18, 47, 49, 48, 
46, 50, 52, 52, 46, 48, 46, 51, 51, 58, 53, 49, 52, 55, 48, 0, 0, 0, 0, 9, 0, 
0, 0, 0, 1, 33, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 29, 106, 97, 110, 117, 
115, 103, 114, 97, 112, 104, 46, 82, 101, 108, 97, 116, 105, 111, 110, 73, 100, 
101, 110, 116, 105, 102, 105, 101,  [...]
                serializer := 
newGraphBinarySerializer(newLogHandler(&defaultLogger{}, Error, 
language.English))
-               response, err := 
serializer.deserializeMessage(responseByteArray)
+               response, err := 
serializer.DeserializeMessage(responseByteArray)
                assert.Nil(t, err)
-               assert.Equal(t, "45de2837-5f3e-4bf9-8685-9b852b97dd44", 
response.responseID.String())
-               assert.Equal(t, uint16(200), response.responseStatus.code)
-               assert.Equal(t, "", response.responseStatus.message)
-               assert.NotNil(t, response.responseResult.data)
+               assert.Equal(t, "45de2837-5f3e-4bf9-8685-9b852b97dd44", 
response.ResponseID.String())
+               assert.Equal(t, uint16(200), response.ResponseStatus.code)
+               assert.Equal(t, "", response.ResponseStatus.message)
 -              assert.Equal(t, map[string]interface{}{"host": 
"/10.244.0.33:51470"}, response.ResponseStatus.attributes)
 -              assert.Equal(t, map[string]interface{}{}, 
response.ResponseResult.Meta)
+               assert.NotNil(t, response.ResponseResult.Data)
        })
  }
  
  func TestSerializerFailures(t *testing.T) {
        t.Run("test convertArgs failure", func(t *testing.T) {
 -              var u, _ = uuid.Parse("41d2e28a-20a4-4ab0-b379-d810dede3786")
                testRequest := request{
 -                      requestID: u,
 -                      op:        "traversal",
 -                      processor: "",
 -                      // Invalid Input in args, so should fail
 -                      args: map[string]interface{}{"invalidInput": 
"invalidInput", "aliases": map[string]interface{}{"g": "g"}},
 +                      // Invalid Input in fields, so should fail
 +                      fields: map[string]interface{}{"invalidInput": 
"invalidInput", "aliases": map[string]interface{}{"g": "g"}},
                }
                serializer := 
newGraphBinarySerializer(newLogHandler(&defaultLogger{}, Error, 
language.English))
-               resp, err := serializer.serializeMessage(&testRequest)
+               resp, err := serializer.SerializeMessage(&testRequest)
                assert.Nil(t, resp)
                assert.NotNil(t, err)
                assert.True(t, 
isSameErrorCode(newError(err0704ConvertArgsNoSerializerError), err))
diff --cc gremlin-go/examples/basic_gremlin.go
index 9586130204,4220b96a4b..628875f4f7
--- a/gremlin-go/examples/basic_gremlin.go
+++ b/gremlin-go/examples/basic_gremlin.go
@@@ -25,8 -26,18 +26,18 @@@ import 
        "github.com/apache/tinkerpop/gremlin-go/v3/driver"
  )
  
 -var serverURL = getEnv("GREMLIN_SERVER_URL", "ws://localhost:8182/gremlin")
++var serverURL = getEnv("GREMLIN_SERVER_URL", "http://localhost:8182/gremlin";)
+ var vertexLabel = getEnv("VERTEX_LABEL", "person")
+ 
+ func getEnv(key, defaultValue string) string {
+       if value := os.Getenv(key); value != "" {
+               return value
+       }
+       return defaultValue
+ }
+ 
  func main() {
-       driverRemoteConnection, err := 
gremlingo.NewDriverRemoteConnection("http://localhost:8182/gremlin";)
+       driverRemoteConnection, err := 
gremlingo.NewDriverRemoteConnection(serverURL)
        if err != nil {
                fmt.Println(err)
                return
diff --cc gremlin-go/examples/connections.go
index c263644c62,15c4ba1744..b2b434934a
--- a/gremlin-go/examples/connections.go
+++ b/gremlin-go/examples/connections.go
@@@ -21,8 -21,21 +21,21 @@@ package mai
  
  import (
        "fmt"
+       "os"
+ 
+       "github.com/apache/tinkerpop/gremlin-go/v3/driver"
  )
  
 -var serverURL = getEnv("GREMLIN_SERVER_URL", "ws://localhost:8182/gremlin")
++var serverURL = getEnv("GREMLIN_SERVER_URL", "http://localhost:8182/gremlin";)
+ var vertexLabel = getEnv("VERTEX_LABEL", "connection")
+ 
+ func getEnv(key, defaultValue string) string {
+       if value := os.Getenv(key); value != "" {
+               return value
+       }
+       return defaultValue
+ }
+ 
  func main() {
        withRemote()
        withConfigs()
diff --cc gremlin-go/examples/modern_traversals.go
index 514196ba21,b722b2812d..053b857fd3
--- a/gremlin-go/examples/modern_traversals.go
+++ b/gremlin-go/examples/modern_traversals.go
@@@ -28,9 -29,20 +29,20 @@@ import 
  var __ = gremlingo.T__
  var T = gremlingo.T
  var P = gremlingo.P
 -var serverURL = getEnv("GREMLIN_SERVER_URL", "ws://localhost:8182/gremlin")
++var serverURL = getEnv("GREMLIN_SERVER_URL", "http://localhost:8182/gremlin";)
+ 
+ func getEnv(key, defaultValue string) string {
+       if value := os.Getenv(key); value != "" {
+               return value
+       }
+       return defaultValue
+ }
  
  func main() {
-       driverRemoteConnection, err := 
gremlingo.NewDriverRemoteConnection("http://localhost:8182/gremlin";)
+       driverRemoteConnection, err := 
gremlingo.NewDriverRemoteConnection(serverURL,
+               func(settings *gremlingo.DriverRemoteConnectionSettings) {
+                       settings.TraversalSource = "gmodern"
+               })
        if err != nil {
                fmt.Println(err)
                return


Reply via email to