Skip to content

Commit

Permalink
Add QWE IoT connector
Browse files Browse the repository at this point in the history
  • Loading branch information
zero88 committed Feb 8, 2021
1 parent da6f299 commit c855f29
Show file tree
Hide file tree
Showing 35 changed files with 1,260 additions and 0 deletions.
5 changes: 5 additions & 0 deletions connector/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# IoT Protocol Connector

## Overview

Defines IoT protocol `connector` interface
9 changes: 9 additions & 0 deletions connector/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
dependencies {
api(project(":data"))
api(ZeroLibs.qwe_protocol)
api(ZeroLibs.qwe_http_metadata)
api(ZeroLibs.qwe_micro_rpc)
api(ZeroLibs.qwe_scheduler_metadata)

testImplementation(testFixtures(ZeroLibs.qwe_base))
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package io.github.zero88.qwe.iot.connector;

import io.github.zero88.qwe.component.HasSharedData;
import io.github.zero88.qwe.component.SharedDataLocalProxy;
import io.github.zero88.qwe.protocol.HasProtocol;

import lombok.Getter;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;
import lombok.experimental.Accessors;

@Getter
@Accessors(fluent = true)
@RequiredArgsConstructor
public abstract class BaseProtocol implements HasSharedData, HasProtocol {

@NonNull
private final SharedDataLocalProxy sharedData;

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package io.github.zero88.qwe.iot.connector;

import io.github.zero88.qwe.component.SharedDataLocalProxy;

import lombok.NonNull;

public abstract class BaseService extends BaseProtocol implements ConnectorService {

protected BaseService(@NonNull SharedDataLocalProxy sharedData) {
super(sharedData);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package io.github.zero88.qwe.iot.connector;

import io.github.zero88.qwe.component.HasSharedData;
import io.github.zero88.qwe.event.EventListener;
import io.github.zero88.qwe.protocol.HasProtocol;

/**
* Represents a connector protocol service
*/
public interface ConnectorService extends EventListener, HasProtocol, HasSharedData {

/**
* Defines service domain name that will be used to distinguish to other domain services.
* <p>
* One {@code domain} service can group multiple {@code function} services. Check {@link FunctionService}.
*
* @return domain name
* @apiNote It is used to generated HTTP path and Event address then it must be unique
*/
String domain();

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package io.github.zero88.qwe.iot.connector;

import java.util.Collections;
import java.util.Set;

import io.github.zero88.qwe.micro.http.ActionMethodMapping;
import io.github.zero88.qwe.micro.http.EventHttpService;
import io.github.zero88.qwe.micro.http.EventMethodDefinition;
import io.github.zero88.utils.Urls;

import lombok.NonNull;

public interface ConnectorServiceApis extends ConnectorService, EventHttpService {

@Override
default String api() {
return String.join(".", domain(), protocol().type().toLowerCase(), getClass().getSimpleName());
}

@Override
default Set<EventMethodDefinition> definitions() {
return Collections.singleton(EventMethodDefinition.create(fullServicePath(), paramPath(), eventMethodMap()));
}

/**
* Full HTTP service path
*
* @return full HTTP service path
*/
default String fullServicePath() {
return Urls.combinePath(domain(), protocol().type().toLowerCase(), servicePath());
}

/**
* Service discovery HTTP path for a specific protocol resource
*
* @return path
*/
@NonNull String servicePath();

/**
* Parameter path for manipulating a specific protocol resource
*
* @return param path
*/
String paramPath();

/**
* Event action and HTTP method mapping
*
* @return event method map
* @see ActionMethodMapping
* @see ConnectorService#getAvailableEvents()
*/
@NonNull ActionMethodMapping eventMethodMap();

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package io.github.zero88.qwe.iot.connector;

import lombok.NonNull;

/**
* Connector function service that interacts with only one particular {@code protocol object} per one time
*
* @see ConnectorService
*/
public interface FunctionService extends ConnectorService {

@NonNull String function();

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package io.github.zero88.qwe.iot.connector;

import io.github.zero88.utils.Urls;

public interface FunctionServiceApis extends FunctionService, ConnectorServiceApis {

default String fullServicePath() {
return Urls.combinePath(domain(), protocol().type().toLowerCase(), servicePath(), function());
}

@Override
default String paramPath() {
return null;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package io.github.zero88.qwe.iot.connector;

import io.github.zero88.qwe.dto.JsonData;
import io.vertx.core.json.JsonObject;

import com.fasterxml.jackson.annotation.JsonProperty;

/**
* Represents for the thing that is being discovered or watched or supervised
*/
public interface Subject extends JsonData {

@JsonProperty("key")
String key();

default JsonObject toDetail() {
return JsonData.super.toJson();
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package io.github.zero88.qwe.iot.connector.command;

import java.util.Collection;
import java.util.Collections;

import io.github.zero88.qwe.dto.msg.RequestData;
import io.github.zero88.qwe.event.EventAction;
import io.github.zero88.qwe.event.EventContractor;
import io.github.zero88.qwe.iot.connector.ConnectorService;
import io.github.zero88.qwe.iot.connector.FunctionService;
import io.reactivex.Single;
import io.vertx.core.json.JsonObject;

import lombok.NonNull;

/**
* Represents for ad-hoc command that send a specific request to a particular {@code protocol device}
*
* @see ConnectorService
*/
public interface Commander extends FunctionService {

@Override
default String domain() {
return "command";
}

@EventContractor(action = "SEND", returnType = Single.class)
Single<JsonObject> send(@NonNull RequestData requestData);

@Override
default @NonNull Collection<EventAction> getAvailableEvents() {
return Collections.singletonList(EventAction.SEND);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package io.github.zero88.qwe.iot.connector.command;

import java.util.Collections;

import io.github.zero88.qwe.event.EventAction;
import io.github.zero88.qwe.iot.connector.FunctionServiceApis;
import io.github.zero88.qwe.micro.http.ActionMethodMapping;
import io.vertx.core.http.HttpMethod;

import lombok.NonNull;

public interface CommanderApis extends Commander, FunctionServiceApis {

@Override
default @NonNull ActionMethodMapping eventMethodMap() {
return ActionMethodMapping.create(Collections.singletonMap(EventAction.SEND, HttpMethod.POST));
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
package io.github.zero88.qwe.iot.connector.coordinator;

import java.util.Arrays;
import java.util.Collection;

import io.github.zero88.qwe.dto.ErrorMessage;
import io.github.zero88.qwe.dto.msg.RequestData;
import io.github.zero88.qwe.event.EventAction;
import io.github.zero88.qwe.event.EventContractor;
import io.github.zero88.qwe.event.EventContractor.Param;
import io.github.zero88.qwe.event.EventPattern;
import io.github.zero88.qwe.event.Waybill;
import io.github.zero88.qwe.iot.connector.ConnectorService;
import io.github.zero88.qwe.iot.connector.FunctionService;
import io.github.zero88.qwe.iot.connector.Subject;
import io.reactivex.Single;
import io.vertx.core.json.JsonObject;

import lombok.NonNull;

/**
* Represents for an {@code coordinator service} that supervises a particular {@code subject} then notifying it to the
* registered {@code subscribers}.
* <p>
* The end-to-end process is named as a {@code coordinator channel}
*
* @param <S> Type of subject
* @see Subject
* @see ConnectorService
*/
public interface Coordinator<S extends Subject> extends FunctionService {

@Override
default String domain() {
return "coordinator";
}

/**
* Register a {@code coordinator channel}
*
* @param requestData request data
* @return coordinator channel
* @see #parseCoordinatorInput(RequestData)
* @see CoordinatorChannel
*/
@EventContractor(action = "CREATE_OR_UPDATE", returnType = Single.class)
Single<CoordinatorChannel> register(@NonNull RequestData requestData);

/**
* Unregister a {@code coordinator channel}
*
* @param requestData request data
* @return coordinator output
* @see CoordinatorChannel
*/
@EventContractor(action = "REMOVE", returnType = Single.class)
Single<CoordinatorChannel> unregister(@NonNull RequestData requestData);

/**
* Query a {@code coordinator channel} by {@code subject}
*
* @param requestData request data
* @return coordinator output
* @see CoordinatorChannel
*/
@EventContractor(action = "GET_ONE", returnType = Single.class)
Single<CoordinatorChannel> get(@NonNull RequestData requestData);

/**
* Defines a handler that listens an event of {@code subject} then notifies to list of {@code subscribers}
*
* @param data subject event data
* @param error error message if any error
* @return true as ack
*/
@EventContractor(action = "MONITOR", returnType = boolean.class)
boolean superviseThenNotify(@Param("data") JsonObject data, @Param("error") ErrorMessage error);

/**
* Parse a coordinator input from request to prepare {@code coordinator channel}
*
* @param requestData request data
* @return coordinator input
*/
@NonNull CoordinatorInput<S> parseCoordinatorInput(@NonNull RequestData requestData);

@Override
default @NonNull Collection<EventAction> getAvailableEvents() {
return Arrays.asList(EventAction.CREATE_OR_UPDATE, EventAction.REMOVE, EventAction.GET_ONE, EventAction.PATCH,
EventAction.MONITOR);
}

/**
* Declares a coordinator address to register a callback address when a {@code subject} notifies an event or change
*
* @return waybill
* @see #superviseThenNotify(JsonObject, ErrorMessage)
* @see Waybill
*/
default Waybill coordinatorInfo() {
return Waybill.builder()
.address(this.getClass().getName())
.action(EventAction.MONITOR)
.pattern(EventPattern.PUBLISH_SUBSCRIBE)
.build();
}

/**
* Defines an {@code subject} address that want to supervise is where a {@code coordinator} can ask
*
* @param payload request data that send to {@code subject} address
* @return waybill
* @see Waybill
*/
Waybill subjectInfo(JsonObject payload);

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package io.github.zero88.qwe.iot.connector.coordinator;

import io.github.zero88.qwe.iot.connector.FunctionServiceApis;
import io.github.zero88.qwe.iot.connector.Subject;
import io.github.zero88.qwe.micro.http.ActionMethodMapping;

import lombok.NonNull;

public interface CoordinatorApis<S extends Subject> extends Coordinator<S>, FunctionServiceApis {

@Override
default @NonNull ActionMethodMapping eventMethodMap() {
return ActionMethodMapping.by(ActionMethodMapping.CRD_MAP, getAvailableEvents());
}

}
Loading

0 comments on commit c855f29

Please sign in to comment.