Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/gh 163 static resource type #164

Merged
merged 5 commits into from
Jun 10, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
63 changes: 54 additions & 9 deletions docs/res-client-protocol.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,28 +56,37 @@ A resource that is referred to with a non-soft [resource reference](res-protocol
## Resource set
Any request or event resulting in new subscriptions will contain a set of resources that contains any subscribed resource previously not subscribed by the client.

The set is grouped by type, `models`, `collections`, and `errors`. Each group is represented by a key/value object where the key is the [resource ID](res-protocol.md#resource-ids), and the value is the [model](res-protocol.md#models), [collection](res-protocol.md#collections), or [error](#error-object).
The set is grouped by type, `models`, `collections`, `statics`, and `errors`. Each group is represented by a key/value object where the key is the [resource ID](res-protocol.md#resource-ids), and the value is the [model](res-protocol.md#models), [collection](res-protocol.md#collections), [static](res-protocol.md#statics), or [error](#error-object).

**Example**
```json
{
"models": {
"messageService.message.1": {
"id": 1,
"msg": "foo"
},
"messageService.message.2": {
"id": 2,
"msg": "bar"
"messageService.overview?start=0&limit=3": {
"total": 123,
"lastSent": 1136239445,
"messages": { "rid": "messageService.messages?start=0&limit=3" }
}
},
"collections": {
"messageService.messages": [
"messageService.messages?start=0&limit=3": [
{ "rid": "messageService.message.1" },
{ "rid": "messageService.message.2" },
{ "rid": "messageService.message.3" }
]
},
"statics": {
"messageService.message.1": {
"id": 1,
"msg": "Application started.",
"data": null
},
"messageService.message.2": {
"id": 2,
"msg": "Email sent to {recipient}.",
"data": { "recipient": "info@example.com" }
}
},
"errors": {
"messageService.message.3": {
"code": "system.notFound",
Expand Down Expand Up @@ -146,6 +155,7 @@ Code | Message | Meaning
`system.noSubscription` | No subscription | The resource has no direct subscription
`system.invalidRequest` | Invalid request | Invalid request
`system.unsupportedProtocol` | Unsupported protocol | RES protocol version is not supported
`system.unsupportedFeature` | Unsupported feature | Feature requires a client supporting a higher RES protocol version


# Requests
Expand Down Expand Up @@ -224,6 +234,10 @@ May be omitted if no new models were subscribed.
[Resource set](#resource-set) collections.
May be omitted if no new collections were subscribed.

**statics**
[Resource set](#resource-set) statics.
May be omitted if no new statics were subscribed.

**errors**
[Resource set](#resource-set) errors.
May be omitted if no subscribed resources encountered errors.
Expand Down Expand Up @@ -280,6 +294,10 @@ May be omitted if no new models were retrieved.
[Resource set](#resource-set) collections.
May be omitted if no new collections were retrieved.

**statics**
[Resource set](#resource-set) statics.
May be omitted if no new statics were retrieved.

**errors**
[Resource set](#resource-set) errors.
May be omitted if no retrieved resources encountered errors.
Expand Down Expand Up @@ -324,6 +342,11 @@ MUST be omitted if **payload** is set.
May be omitted if no new collections were subscribed.
MUST be omitted if **payload** is set.

**statics**
[Resource set](#resource-set) statics.
May be omitted if no new statics were subscribed.
MUST be omitted if **payload** is set.

**errors**
[Resource set](#resource-set) errors.
May be omitted if no subscribed resources encountered errors.
Expand Down Expand Up @@ -366,6 +389,16 @@ MUST be omitted if **payload** is set.
May be omitted if no new collections were subscribed.
MUST be omitted if **payload** is set.

**statics**
[Resource set](#resource-set) statics.
May be omitted if no new statics were subscribed.
MUST be omitted if **payload** is set.

**errors**
[Resource set](#resource-set) errors.
May be omitted if no subscribed resources encountered errors.
MUST be omitted if **payload** is set.

### Error
An error response will be sent if the method couldn't be called, or if the authentication failed.

Expand Down Expand Up @@ -397,6 +430,10 @@ May be omitted if no new models were subscribed.
[Resource set](#resource-set) collections.
May be omitted if no new collections were subscribed.

**statics**
[Resource set](#resource-set) statics.
May be omitted if no new statics were subscribed.

**errors**
[Resource set](#resource-set) errors.
May be omitted if no subscribed resources encountered errors.
Expand Down Expand Up @@ -451,6 +488,10 @@ May be omitted if no new models were subscribed.
[Resource set](#resource-set) collections.
May be omitted if no new collections were subscribed.

**statics**
[Resource set](#resource-set) statics.
May be omitted if no new statics were subscribed.

**errors**
[Resource set](#resource-set) errors.
May be omitted if no subscribed resources encountered errors.
Expand Down Expand Up @@ -500,6 +541,10 @@ May be omitted if no new models were subscribed.
[Resource set](#resource-set) collections.
May be omitted if no new collections were subscribed.

**statics**
[Resource set](#resource-set) statics.
May be omitted if no new statics were subscribed.

**errors**
[Resource set](#resource-set) errors.
May be omitted if no subscribed resources encountered errors.
Expand Down
16 changes: 15 additions & 1 deletion docs/res-protocol.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
* [Resource IDs](#resource-ids)
* [Models](#models)
* [Collections](#collections)
* [Statics](#statics)
* [Values](#values)
* [Resource references](#resource-references)
* [Messaging system](#messaging-system)
Expand All @@ -34,7 +35,7 @@ This document gives an overview of the protocol and its features, and describes

## Resources

RES protocol is built around a concept of resources. A resource may be either be a [*model*](#models) or a [*collection*](#collections). Each resource (model or collection) is identified by a unique [*resource ID*](#resource-ids), also called *rid* for short.
RES protocol is built around a concept of resources. A resource may be either be a [*model*](#models), a [*collection*](#collections), or a [*static*](#statics). Each resource (model, collection, or static) is identified by a unique [*resource ID*](#resource-ids), also called *rid* for short.

## Resource IDs
A *resource ID* is a string that consist of a *resource name* and an optional *query*.
Expand Down Expand Up @@ -77,6 +78,19 @@ A collection is an ordered list of [values](#values) represented by a JSON array
[ "admin", "tester", "developer" ]
```

## Statics

A static resource is immutable arbitrary data represented by any JSON value.

**Example**
```json
{
"timestamp": 1136239445,
"log": "Email sent to {to}.",
"params": { "to": "info@example.com" }
}
```

## Values

A value is either a *primitive* or a [resource reference](#resource-references).
Expand Down
29 changes: 19 additions & 10 deletions docs/res-service-protocol.md
Original file line number Diff line number Diff line change
Expand Up @@ -186,11 +186,15 @@ MUST be a string.

**model**
An object containing the named properties and [values](res-protocol.md#values) of the model.
MUST be omitted if *collection* is provided.
MUST be omitted if *collection* or *static* is provided.

**collection**
An ordered array containing the [values](res-protocol.md#values) of the collection.
MUST be omitted if *model* is provided.
MUST be omitted if *model* or *static* is provided.

**static**
An arbitrary JSON value.
MUST be omitted if *model* or *collection* is provided.

**query**
Normalized query without the question mark separator.
Expand Down Expand Up @@ -328,7 +332,7 @@ A set request is used to update or delete a model's properties.
**Parameters**
The parameters SHOULD be a key/value object describing the properties to be changed. Each property should have a new [value](res-protocol.md#values) or a [delete action](#delete-action). Unchanged properties SHOULD NOT be included.
If any of the model properties are changed, a [model change event](#model-change-event) MUST be sent prior to sending the response.
MUST NOT be sent on [collections](res-protocol.md#collections).
SHOULD NOT be sent on [collections](res-protocol.md#collections) or [statics](res-protocol.md#statics).

## New call request

Expand Down Expand Up @@ -374,7 +378,7 @@ When a resource is modified, the service MUST send the defined events that descr
`event.<resourceName>.change`

Change events are sent when a [model](res-protocol.md#models)'s properties has been changed.
MUST NOT be sent on [collections](res-protocol.md#collections).
MUST NOT be sent on other resource types.
The event payload has the following parameter:

**values**
Expand Down Expand Up @@ -405,7 +409,7 @@ A delete action is a JSON object used when a property has been deleted from a mo

Add events are sent when a value is added to a [collection](res-protocol.md#collections).
Any previous value at the same index or higher will implicitly be shifted one step to a higher index.
MUST NOT be sent on [models](res-protocol.md#models).
MUST NOT be sent on other resource types.
The event payload has the following parameters:

**value**
Expand All @@ -430,7 +434,7 @@ MUST be a number that is zero or greater and less than or equal to the length of

Remove events are sent when a value is removed from a [collection](res-protocol.md#collections).
Any previous value at a higher index will implicitly be shifted one step to a lower index.
MUST NOT be sent on [models](res-protocol.md#models).
MUST NOT be sent on other resource types.
The event payload has the following parameter:

**idx**
Expand Down Expand Up @@ -551,7 +555,7 @@ Eg. `messageService.>` - Pattern that matches all resources owned by *messageSer

# Query resources

A query resource is a resource where its model properties or collection values may vary based on the query. It is used to request partial or filtered resources, such as for searches, sorting, or pagination.
A query resource is a resource where its model, collection, or static values may vary based on the query. It is used to request partial or filtered resources, such as for searches, sorting, or pagination.

## Query event

Expand Down Expand Up @@ -600,18 +604,23 @@ MUST be a string.
An array of events for the query resource.
MUST be an array of [event query objects](#event-query-object)
May be omitted if there are no events.
Must be omitted if *model* or *collection* is provided.
Must be omitted if *model*, *collection*, or *static* is provided.

**model**
An object containing the named properties and [values](res-protocol.md#values) of the model.
Must be omitted if *events* or *collection* is provided.
Must be omitted if *events*, *collection*, or *static* is provided.
Must be omitted if the query resource is not a model.

**collection**
An ordered array containing the [values](res-protocol.md#values) of the collection.
Must be omitted if *events* or *model* is provided.
Must be omitted if *events*, *model*, or *static* is provided.
Must be omitted if the query resource is not a collection.

**static**
An arbitrary JSON value.
Must be omitted if *events*, *model*, or *collection* is provided.
Must be omitted if the query resource is not a static.

**Example result payload with events**
```json
{
Expand Down
9 changes: 9 additions & 0 deletions server/apiEncoding.go
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,12 @@ func (e *encoderJSON) encodeSubscription(s *Subscription, wrap bool) error {
}
}
e.b.WriteByte('}')

case rescache.TypeStatic:
if wrap {
e.b.Write([]byte(`,"static":`))
}
e.b.Write(s.Static())
}

// Remove itself from path
Expand Down Expand Up @@ -379,6 +385,9 @@ func (e *encoderJSONFlat) encodeSubscription(s *Subscription) error {
}
}
e.b.WriteByte('}')

case rescache.TypeStatic:
e.b.Write(s.Static())
}

// Remove itself from path
Expand Down
9 changes: 7 additions & 2 deletions server/codec/codec.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ type GetResponse struct {
type GetResult struct {
Model map[string]Value `json:"model"`
Collection []Value `json:"collection"`
Static json.RawMessage `json:"static"`
Query string `json:"query"`
}

Expand Down Expand Up @@ -115,6 +116,7 @@ type EventQueryResult struct {
Events []*EventQueryEvent `json:"events"`
Model map[string]Value `json:"model"`
Collection []Value `json:"collection"`
Static json.RawMessage `json:"static"`
}

// EventQueryEvent represents an event in the response of a RES-server query request
Expand Down Expand Up @@ -329,7 +331,7 @@ func DecodeGetResponse(payload []byte) (*GetResult, error) {
// Assert we got either a model or a collection
res := r.Result
if res.Model != nil {
if res.Collection != nil {
if res.Collection != nil || res.Static != nil {
return nil, errInvalidResponse
}
// Assert model only has proper values
Expand All @@ -339,13 +341,16 @@ func DecodeGetResponse(payload []byte) (*GetResult, error) {
}
}
} else if res.Collection != nil {
if res.Static != nil {
return nil, errInvalidResponse
}
// Assert collection only has proper values
for _, v := range res.Collection {
if !v.IsProper() {
return nil, errInvalidResponse
}
}
} else {
} else if res.Static == nil {
return nil, errInvalidResponse
}

Expand Down
12 changes: 10 additions & 2 deletions server/rescache/eventSubscription.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ type ResourceType byte
const (
TypeCollection ResourceType = ResourceType(stateCollection)
TypeModel ResourceType = ResourceType(stateModel)
TypeStatic ResourceType = ResourceType(stateStatic)
TypeError ResourceType = ResourceType(stateError)
)

Expand Down Expand Up @@ -102,7 +103,7 @@ func (e *EventSubscription) addSubscriber(sub Subscriber) {
defer e.mu.Lock()
sub.Loaded(nil, rs.err)

// stateModel or stateCollection
// stateModel, stateCollection, or stateStatic
default:
e.mu.Unlock()
defer e.mu.Lock()
Expand Down Expand Up @@ -307,10 +308,17 @@ func (e *EventSubscription) handleQueryEvent(subj string, payload []byte) {
// Handle collection response
case result.Collection != nil:
if rs.state != stateCollection {
e.cache.Errorf("Error processing query event for %s?%s: non-model payload on model %s", e.ResourceName, rs.query, data)
e.cache.Errorf("Error processing query event for %s?%s: non-collection payload on collection %s", e.ResourceName, rs.query, data)
return
}
rs.processResetCollection(result.Collection)
// Handle static response
case result.Static != nil:
if rs.state != stateStatic {
e.cache.Errorf("Error processing query event for %s?%s: non-static payload on static %s", e.ResourceName, rs.query, data)
return
}
rs.processResetStatic(result.Static)
}
})
})
Expand Down
Loading