Usage Guide
Learn the fastest mental model first, then copy the service-side and edge-side patterns you need.
Run examples
Use chatroom for messaging and presence, or RTMP for streams.
Services connect to :30011. Edges connect to :30012. Service -> edge usually targets a specific edgeID.
Frontier uses one service-to-edge model for RPC, messaging, and streams instead of treating them as separate systems.
Start with the right example
- Choose chatroom if you want to understand presence, messaging, and the basic long-lived connection model.
- Choose rtmp if you care about proxying traffic, file transfer, media relay, or other point-to-point stream use cases.
- Return to this page once you know which SDK pattern you need to copy into production code.
Using Frontier in Microservices
1. Getting the Service Client
To connect your microservice to Frontier, use the NewService method with a dialer connecting to the Service port (default: 30011).
package main
import (
"net"
"github.com/singchia/frontier/api/dataplane/v1/service"
)
func main() {
dialer := func() (net.Conn, error) {
return net.Dial("tcp", "127.0.0.1:30011")
}
svc, err := service.NewService(dialer)
// Start using the service
}2. Handling Edge Presence (Online/Offline)
You can register callbacks to know when Edge nodes connect or disconnect from the gateway.
func main() {
// ... dialer setup ...
svc, _ := service.NewService(dialer)
// Register lifecycle hooks
svc.RegisterGetEdgeID(context.TODO(), getID)
svc.RegisterEdgeOnline(context.TODO(), online)
svc.RegisterEdgeOffline(context.TODO(), offline)
}
// Service can assign IDs based on edge metadata
func getID(meta []byte) (uint64, error) {
return 0, nil
}
func online(edgeID uint64, meta []byte, addr net.Addr) error {
fmt.Printf("Edge %d is online\n", edgeID)
return nil
}
func offline(edgeID uint64, meta []byte, addr net.Addr) error {
fmt.Printf("Edge %d is offline\n", edgeID)
return nil
}3. Service to Edge RPC (Command & Control)
A Service can execute a method directly on an Edge node by its edgeID.
func main() {
// ... dialer setup ...
svc, _ := service.NewService(dialer)
req := svc.NewRequest([]byte("payload data"))
// Call the "reboot" method on Edge ID 1001
rsp, err := svc.Call(context.TODO(), 1001, "reboot", req)
if err != nil {
log.Fatal(err)
}
}Using Frontier on Edge Nodes
1. Getting the Edge Client
Edge nodes (IoT devices, agents, clients) connect to the Edge port (default: 30012). You must provide a unique Edge ID if the Service isn't allocating them.
package main
import (
"net"
"github.com/singchia/frontier/api/dataplane/v1/edge"
)
func main() {
dialer := func() (net.Conn, error) {
return net.Dial("tcp", "127.0.0.1:30012")
}
// Connect with a specific Edge ID
opt := edge.OptionEdgeID("edge-node-01")
eg, err := edge.NewEdge(dialer, opt)
if err != nil {
panic(err)
}
}2. Edge Registers RPC for Service to Call
For the Service to be able to issue commands to the Edge, the Edge must register methods.
func main() {
// ... edge setup ...
// Register the "reboot" method
eg.Register(context.TODO(), "reboot", handleReboot)
}
func handleReboot(ctx context.Context, req geminio.Request, rsp geminio.Response) {
// Execute reboot logic
log.Println("Received reboot command")
// Send response back
rsp.SetData([]byte("rebooting..."))
}3. Edge Publishes Telemetry (Messaging)
Edges can publish data to specific Topics. Frontier routes this to Services that have subscribed to the topic, or forwards it to an external MQ like Kafka.
func main() {
// ... edge setup ...
msg := eg.NewMessage([]byte(`{"temp": 42.5}`))
// Publish to the "sensor/temperature" topic
err := eg.Publish(context.TODO(), "sensor/temperature", msg)
}Advanced: Point-to-Point Streams
If you need to transfer large files or proxy custom protocol traffic such as SSH, VNC, or RTMP, you can open a direct multiplexed stream.
Service Opening a Stream to an Edge
func main() {
// ... service setup ...
// Open a new stream to Edge ID 1001.
// st implements net.Conn, so you can use it like a raw TCP socket!
st, err := svc.OpenStream(context.TODO(), 1001)
// Proxy SSH traffic, relay media, or write files directly
io.Copy(st, fileData)
}