]> asedeno.scripts.mit.edu Git - cl-protobufs.git/commitdiff
Add stub support for streaming RPC APIs.
authorScott McKay <swm@google.com>
Tue, 4 Sep 2012 18:36:57 +0000 (18:36 +0000)
committerScott McKay <swm@google.com>
Tue, 4 Sep 2012 18:36:57 +0000 (18:36 +0000)
Testing : precheckin --full --strict-errors
Reviewer: Fare (please)

JTB impact: No
Ops impact: No

Change to config                        : No
Change to XML schema                    : No
Change to DB schema                     : No
Change to transport (timeouts, headers) : No
Any change (or new use) of OAQs         : No
Change to inter-component transactions  : No
Depends on any other checkin / bug      : No

Tests that will verify:

I extended the CL-Protobufs tests

Description:

Add support for a 'streams' type in Protobufs RPC methods.
 - Add a few slots to 'protobufs-method'
 - Add '&key streams' to the method arglists in 'define-service'
 - Extend the parser to handle "streams" in addition to the
   'streams_type' option
 - Extend the printer
 - Change a test to use a 'streams' type
 - While we're in the neighborhood, allow an optional '=>'
   between the input and output methods in 'define-service';
   it makes it a bit more readable
 - Update the documentation

git-svn-id: http://svn.internal.itasoftware.com/svn/ita/trunk/qres/lisp/libs/cl-protobufs@560147 f8382938-511b-0410-9cdd-bb47b084005c

cl-protobufs.rst
define-proto.lisp
examples.lisp
model-classes.lisp
parser.lisp
pkgdcl.lisp
printer.lisp
tests/serialization-tests.lisp
tests/stability-tests.lisp

index 8bf07376fe2049f5c6540b766e68c096e47975ec..ab22dddaad23c9d3263eef49bc4668adbb37deff 100644 (file)
@@ -330,9 +330,9 @@ following macros. For example::
       (color :type color))
     (proto:define-service color-wheel ()
       (get-color (get-color-request color)
-        :options ("deadline" "1.0"))
+        :options (:deadline 1.0))
       (add-color (add-color-request color)
-        :options ("deadline" "1.0"))))
+        :options (:deadline 1.0))))
 
 This will create the Protobufs model objects, Lisp classes and enum
 types that correspond to the model. The .proto file of the same schema
@@ -373,10 +373,10 @@ looks something like this::
 
   service ColorWheel {
     rpc GetColor (GetColorRequest) returns (Color) {
-      option deadline = "1.0";
+      option deadline = 1.0;
     }
     rpc AddColor (AddColorRequest) returns (Color) {
-      option deadline = "1.0";
+      option deadline = 1.0;
     }
   }
 
@@ -610,9 +610,16 @@ the Protobufs name is the string *name*.
 in the .proto file.
 
 The body is a set of method specs of the form
-``(name (input-type output-type) &key options documentation)``.
-*name* is a symbol naming the RPC method. *input-type* and
-*output-type* may either be symbols or a list of the form ``(type &key name)``.
+``(name (input-type [=>] output-type &key streams) &key options documentation)``.
+
+For each method spec, *name* is a symbol naming the RPC method.
+*input-type* and *output-type* give the input and output types of the method;
+they may either be symbols or a list of the form ``(type &key name)``.
+You can optionally include the symbol ``=>`` between the input and
+output types; this seems to improve readability.
+
+*streams* is also the name of a type, and provides a hook to RPC
+implementations that implement "streaming".
 
 ``proto:define-service`` can only be used within ``proto:define-schema``.
 
index 042cc3ac09e795ffae6319a1ed5aae9532b48dd2..2b5a5cb9d292acb3805215fcb09b16d7d97c61c2 100644 (file)
    'name' can be used to override the defaultly generated Protobufs service name.
    'options' is a set of keyword/value pairs, both of which are strings.
 
-   The body is a set of method specs of the form (name (input-type output-type) &key options).
+   The body is a set of method specs of the form (name (input-type [=>] output-type) &key options).
    'input-type' and 'output-type' may also be of the form (type &key name)."
   (let* ((name    (or name (class-name->proto type)))
          (options (loop for (key val) on options by #'cddr
          (index 0))
     (with-collectors ((forms collect-form))
       (dolist (method method-specs)
-        (destructuring-bind (function (input-type output-type)
+        (destructuring-bind (function (&rest types)
                              &key name options documentation source-location) method
-          (let* ((input-name (and (listp input-type)
+          (let* ((input-type   (first types))
+                 (output-type  (if (string= (string (second types)) "=>") (third types) (second types)))
+                 (streams-type (if (string= (string (second types)) "=>")
+                                 (getf (cdddr types) :streams)
+                                 (getf (cddr  types) :streams)))
+                 (input-name (and (listp input-type)
                                   (getf (cdr input-type) :name)))
                  (input-type (if (listp input-type) (car input-type) input-type))
                  (output-name (and (listp output-type)
                                    (getf (cdr output-type) :name)))
                  (output-type (if (listp output-type) (car output-type) output-type))
+                 (streams-name (and (listp streams-type)
+                                    (getf (cdr streams-type) :name)))
+                 (streams-type (if (listp streams-type) (car streams-type) streams-type))
                  (options (loop for (key val) on options by #'cddr
                                 collect (make-instance 'protobuf-option
                                           :name  (if (symbolp key) (slot-name->proto key) key)
                             :input-name  (or input-name (class-name->proto input-type))
                             :output-type output-type
                             :output-name (or output-name (class-name->proto output-type))
+                            :streams-type streams-type
+                            :streams-name (and streams-type
+                                               (or streams-name (class-name->proto streams-type)))
                             :index (iincf index)
                             :options options
                             :documentation documentation
 (defgeneric ensure-method (trace service method)
   (:method (trace service (method protobuf-method))
     (ensure-type trace service method (proto-input-type method))
-    (ensure-type trace service method (proto-output-type method))))
+    (ensure-type trace service method (proto-output-type method))
+    (ensure-type trace service method (proto-streams-type method))))
 
 ;; 'message' and 'field' can be a message and a field or a service and a method
 (defun ensure-type (trace message field type)
index 91c8a7b62e21cee25af5b4e2d5b934b2dad2172b..1ff8d53d117f5b303680a1a546f989b698ebb4e1 100644 (file)
     (wheel :type color-wheel)
     (color :type color))
   (proto:define-service color-wheel ()
-    (get-color (get-color-request color)
-      :options ("deadline" 1.0)
+    (get-color (get-color-request => color)
+      :options (:deadline 1.0)
       :documentation "Look up a color by name")
-    (add-color (add-color-request color)
-      :options ("deadline" 1.0)
+    (add-color (add-color-request => color)
+      :options (:deadline 1.0)
       :documentation "Add a new color to the wheel")))
 
 (proto:write-schema *color-wheel*)
index e1015b8b88d0f0ca1447e17a64ea078c1d41472d..a101773552ff4ed3459409fc6b17f342ad536849 100644 (file)
           :initarg :value
           :initform nil)
    (type :type (or null symbol)                 ;(optional) Lisp type,
-         :reader proto-type                     ;  one of string, integer, sybol (for now)
+         :reader proto-type                     ;  one of string, integer, float, symbol (for now)
          :initarg :type
          :initform 'string))
   (:documentation
           :accessor proto-output-name
           :initarg :output-name
           :initform nil)
+   (stype :type (or symbol null)                ;the Lisp type name of the "streams" type
+          :accessor proto-streams-type
+          :initarg :streams-type
+          :initform nil)
+   (sname :type (or null string)                ;the Protobufs name of the "streams" type
+          :accessor proto-streams-name
+          :initarg :streams-name
+          :initform nil)
    (index :type (unsigned-byte 32)              ;an identifying index for this method
           :accessor proto-index                 ; (used by the RPC implementation)
           :initarg :index))
index 0210f352d37e667342e0ab70c7e04c46792c7819..3ef687a7affb7e5c9278a34566e767e6fa1d6655 100644 (file)
          (in   (prog2 (expect-char stream #\( () "service")
                    (parse-token stream)
                  (expect-char stream #\) () "service")))
-         (ret  (parse-token stream))
+         (ret  (parse-token stream))            ;should be "=>"
          (out  (prog2 (expect-char stream #\( () "service")
                    (parse-token stream)
                  (expect-char stream #\) () "service")))
+         (strm (parse-token stream))            ;might be "streams"
+         (strm (and strm (string= strm "streams")
+                    (prog2 (expect-char stream #\( () "service")
+                        (parse-token stream)
+                      (expect-char stream #\) () "service"))))
          (opts (let ((opts (parse-proto-method-options stream)))
                  (when (or (null opts) (eql (peek-char nil stream nil) #\;))
                    (expect-char stream #\; () "service"))
                    :input-name  in
                    :output-type (proto->class-name out *protobuf-package*)
                    :output-name out
+                   :streams-type (and strm (proto->class-name strm *protobuf-package*))
+                   :streams-name strm
                    :index index
                    :options opts
                    :source-location (make-source-location stream loc (i+ loc (length name))))))
+    (assert (string= ret "returns") ()
+            "Syntax error in 'message' at position ~D" (file-position stream))
     (let* ((name (find-option method "lisp_name"))
            (stub (or (and name (make-lisp-symbol name))
                      stub)))
       (setf (proto-class method) stub
             (proto-client-stub method) stub
             (proto-server-stub method) (intern (format nil "~A-~A" 'do stub) *protobuf-package*)))
-    (assert (string= ret "returns") ()
-            "Syntax error in 'message' at position ~D" (file-position stream))
     (setf (proto-methods service) (nconc (proto-methods service) (list method)))
     method))
 
index 26ab76e0a54db5cf1d32703f41a1fd6195ea85f4..474ff53a48d1aa56202a3bbbbff66ccce5fa531d 100644 (file)
    "PROTO-SERVICES"
    "PROTO-SLOT"
    "PROTO-SOURCE-LOCATION"
+   "PROTO-STREAMS-NAME"
+   "PROTO-STREAMS-TYPE"
    "PROTO-SYNTAX"
    "PROTO-TYPE"
    "PROTO-VALUE"
index 266ecd71880cc5241bdfe07464283b8aa2e8be42..7844ff26c170173c8a43afc2f67ef2296f767cd1 100644 (file)
@@ -91,6 +91,7 @@
                          ("deprecated"            symbol)
                          ("optimize_for"          symbol)
                          ("packed"               boolean)
+                         ("protocol"              symbol)
                          ("stream_type"           string)
                          ;; Keep the rest of these in alphabetical order
                          ("cc_api_version"       integer)
                            ((boolean) "~A~@[ = ~(~A~)~]")
                            (otherwise "~A~@[ = ~S~]"))))))
              (format stream fmt-control (proto-name option) (proto-value option))))
-          (atsign-p                             ;~@/protobuf-option/ -- .lisp format
+          (atsign-p                             ;~@/protobuf-option/ -- string/value format
            (let ((fmt-control (if (eq type 'symbol) "~(~S~) ~A" "~(~S~) ~S")))
              (format stream fmt-control (proto-name option) (proto-value option))))
           (t                                    ;~/protobuf-option/  -- keyword/value format
                             &key (indentation 0) more)
   (declare (ignore more))
   (with-prefixed-accessors
-      (name documentation input-name output-name options) (proto- method)
+      (name documentation input-name output-name streams-name options) (proto- method)
     (let* ((imsg (find-message *protobuf* input-name))
            (omsg (find-message *protobuf* output-name))
+           (smsg (find-message *protobuf* streams-name))
            (iname (maybe-qualified-name imsg))
-           (oname (maybe-qualified-name omsg)))
+           (oname (maybe-qualified-name omsg))
+           (sname (maybe-qualified-name smsg)))
       (when documentation
         (write-schema-documentation type documentation stream :indentation indentation))
-      (format stream "~&~@[~VT~]rpc ~A (~@[~A~])~@[ returns (~A)~]"
+      (format stream "~&~@[~VT~]rpc ~A (~@[~A~])~@[ streams (~A)~]~@[ returns (~A)~]"
               (and (not (zerop indentation)) indentation)
-              name iname oname)
+              name iname sname oname)
       (cond (options
              (format stream " {~%")
              (dolist (option options)
             (terpri stream))
           (setq spaces "     "))
         (when options
-          (format stream "~A:options (~{~@/protobuf-option/~^ ~})" spaces options)
+          (format stream "~A:options (~{~/protobuf-option/~^ ~})" spaces options)
           (when documentation
             (terpri stream))
           (setq spaces "     "))
                                 ;; Keyword class means a primitive type, print default with ~S
                                 "~&~@[~VT~](~A :type ~(~S~)~:[~*~; :default ~S~]~
                                  ~@[ :reader ~(~S~)~]~@[ :writer ~(~S~)~]~@[ :packed ~(~S~)~]~
-                                 ~@[ :options (~{~@/protobuf-option/~^ ~})~])~
+                                 ~@[ :options (~{~/protobuf-option/~^ ~})~])~
                                  ~:[~*~*~;~VT; ~A~]"
                                 ;; Non-keyword class means an enum type, print default with ~(~S~)
                                 "~&~@[~VT~](~A :type ~(~S~)~:[~*~; :default ~(~S~)~]~
                                  ~@[ :reader ~(~S~)~]~@[ :writer ~(~S~)~]~@[ :packed ~(~S~)~]~
-                                 ~@[ :options (~{~@/protobuf-option/~^ ~})~])~
+                                 ~@[ :options (~{~/protobuf-option/~^ ~})~])~
                                  ~:[~*~*~;~VT; ~A~]")
                        (and (not (zerop indentation)) indentation)
                        slot-name type defaultp default reader writer packed options
 (defmethod write-schema-as ((type (eql :lisp)) (method protobuf-method) stream
                             &key (indentation 0) more)
   (declare (ignore more))
-  (with-prefixed-accessors (class input-type output-type options
+  (with-prefixed-accessors (class input-type output-type streams-type options
                             documentation source-location) (proto- method)
     (when documentation
       (write-schema-documentation type documentation stream :indentation indentation))
-    (format stream "~&~@[~VT~](~(~S~) (~(~S~) ~(~S~))"
+    (format stream "~&~@[~VT~](~(~S~) (~(~S~) => ~(~S~)~@[ :streams ~(~S~)~])"
             (and (not (zerop indentation)) indentation)
-            class input-type output-type)
+            class input-type output-type streams-type)
     (when options
-      (format stream "~%~VT:options (~{~@/protobuf-option/~^ ~})"
+      (format stream "~%~VT:options (~{~/protobuf-option/~^ ~})"
               (+ indentation 2) options))
     (format stream ")")))
 
index 402babcf2f56e48278a9d6800af53e9e90eb68b0..752c71d9813ba6337200f3322e8517f159425a1e 100644 (file)
   (proto:define-message buy-car-response ()
     (price :type (or null uint32)))
   (proto:define-service buy-car ()
-    (buy-car (buy-car-request buy-car-response)
+    (buy-car (buy-car-request => buy-car-response)
       :options (:deadline 1.0))))
 
 (define-test extension-serialization ()
index 5a8531ed9088ea5e5e0c7ac14564e3efcaad5285..959552bce5844d332e8b241ef8693fade9a20280 100644 (file)
@@ -36,8 +36,8 @@
     (wheel :type stable-color-wheel)
     (color :type stable-color))
   (proto:define-service stable-color-wheel ()
-    (get-stable-color (string stable-color))
-    (set-stable-color (stable-color stable-color)
+    (get-stable-color (string => stable-color))
+    (set-stable-color (stable-color => stable-color)
                       :options (:deadline 1.0))))
 
 (defvar *color-wheel-proto*