Skip to content

Commit

Permalink
Merge pull request #12 from JuliaMessaging/feature/mock-broker
Browse files Browse the repository at this point in the history
Create a Mock Broker
  • Loading branch information
NickMcSweeney authored May 29, 2024
2 parents 7407565 + d71bdd2 commit 6fcc30f
Show file tree
Hide file tree
Showing 26 changed files with 910 additions and 785 deletions.
5 changes: 5 additions & 0 deletions .JuliaFormatter.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# See https://domluna.github.io/JuliaFormatter.jl/stable/ for a list of options

style = "blue"

format_docstrings = true
8 changes: 6 additions & 2 deletions .github/workflows/CI.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,18 @@ jobs:
fail-fast: false
matrix:
version:
- '1.8'
- '1.8' # minimum version
- '1.9'
- '1.10'
- '1'
os:
- ubuntu-latest
- macOS-latest
- windows-latest
arch:
- x64
steps:
- name: Install mosquitto
if: runner.os == 'Linux'
run: |
sudo apt-get update
sudo apt-get install mosquitto
Expand All @@ -39,6 +42,7 @@ jobs:
- uses: julia-actions/cache@v1
- uses: julia-actions/julia-buildpkg@v1
- name: Run mosquitto broker
if: runner.os == 'Linux'
run: |
sudo systemctl stop mosquitto
sudo cp ${{ github.workspace }}/test/testclient/mosquitto.test.config /etc/mosquitto/conf.d/test.conf
Expand Down
47 changes: 47 additions & 0 deletions .github/workflows/JuliaFormatter.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
name: Code Formatting

on:
pull_request:
branches:
- main

jobs:
format:
runs-on: ubuntu-latest

permissions:
contents: write
pull-requests: write
actions: write

steps:
- name: Cancel Previous Runs
uses: styfle/[email protected]

- uses: actions/checkout@v4
with:
ref: ${{ github.head_ref }}

- uses: julia-actions/setup-julia@v2
with:
version: 1.9

- name: Install JuliaFormatter and format
shell: bash
run: julia -e 'import Pkg; Pkg.add("JuliaFormatter"); using JuliaFormatter; format(".")'

- name: Create Pull Request
id: pr
uses: peter-evans/create-pull-request@v6
with:
commit-message: Format files using JuliaFormatter
title: ${{ format('[AUTO] Format {0} using JuliaFormatter', github.event.pull_request.number) }}
body: ${{ format('[JuliaFormatter.jl](https://github.com/domluna/JuliaFormatter.jl) would suggest these formatting changes against \#{0}.', github.event.pull_request.number) }}
labels: no changelog
branch: ${{ format('code-format/{0}', github.event.pull_request.number) }}
delete-branch: true

- name: Fail if a PR was needed
if: ${{ steps.pr.outputs.pull-request-operation == 'created' || steps.pr.outputs.pull-request-operation == 'updated' }}
shell: bash
run: exit 1
4 changes: 2 additions & 2 deletions Project.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name = "MQTTClient"
uuid = "985f35cc-2c3d-4943-b8c1-f0931d5f0959"
authors = ["Nick Shindler <[email protected]>"]
version = "0.3.0"
version = "0.3.1"

[deps]
Distributed = "8ba89e20-285c-5b6f-9357-94700520ee1b"
Expand All @@ -15,7 +15,7 @@ PrecompileTools = "aea7be01-6a6a-4083-8856-8a6e6704d82a"
PrecompileMQTT = "PrecompileTools"

[compat]
julia = "1.7"
julia = "1.8"

[extras]
Dates = "ade2ca70-3891-5945-98fb-dc099432e06a"
Expand Down
1 change: 0 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
[![Dev](https://img.shields.io/badge/docs-dev-blue.svg)](https://JuliaMessaging.github.io/MQTTClient.jl/dev/)
[![Build Status](https://github.com/JuliaMessaging/MQTTClient.jl/actions/workflows/CI.yml/badge.svg?branch=main)](https://github.com/JuliaMessaging/MQTTClient.jl/actions/workflows/CI.yml?query=branch%3Amain)
[![Coverage](https://codecov.io/gh/JuliaMessaging/MQTTClient.jl/branch/main/graph/badge.svg)](https://codecov.io/gh/JuliaMessaging/MQTTClient.jl)
[![Coverage](https://coveralls.io/repos/github/JuliaMessaging/MQTTClient.jl/badge.svg?branch=main)](https://coveralls.io/github/JuliaMessaging/MQTTClient.jl?branch=main)
[![Code Style: Blue](https://img.shields.io/badge/code%20style-blue-4495d1.svg)](https://github.com/invenia/BlueStyle)

MQTT Client Library for Julia
Expand Down
13 changes: 4 additions & 9 deletions docs/make.jl
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
push!(LOAD_PATH,"../src/")
push!(LOAD_PATH, "../src/")

using MQTTClient
using Documenter
Expand All @@ -21,15 +21,10 @@ makedocs(;
"Getting Started" => "getting-started.md",
"MQTT Interface Functions" => "interfaces.md",
"MQTT Client" => "client.md",
"MQTT API" => [
"Client" => "api/client.md",
"Interfacing Functions" => "api/interface.md",
],
"MQTT API" =>
["Client" => "api/client.md", "Interfacing Functions" => "api/interface.md"],
"Utils" => "utils.md",
],
)

deploydocs(;
repo="github.com/JuliaMessaging/MQTTClient.jl",
devbranch="main",
)
deploydocs(; repo="github.com/JuliaMessaging/MQTTClient.jl", devbranch="main")
3 changes: 2 additions & 1 deletion docs/src/api/client.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
```@docs
Client
MQTTConnection
Connection
IOConnection
MQTTClient.Message
User
Configuration
```
4 changes: 2 additions & 2 deletions docs/src/getting-started.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,9 @@ using MQTTClient

## Getting started
To use this library you need to follow at least these steps:
1. Create an `MQTTConnection` struct for a given broker and protocol.
1. Create an `Connection` struct for a given broker and protocol.
2. Create an instance of the `Client` struct.
3. Call the connect method with your `Client` and `MQTTConnection` instance.
3. Call the connect method with your `Client` and `Connection` instance.
4. Exchange data with the broker through publish, subscribe and unsubscribe. When subscribing, pass your `on_msg` function for that topic.
5. Disconnect from the broker. (Not strictly necessary, if you don't want to resume the session but considered good form and less likely to crash).

Expand Down
2 changes: 1 addition & 1 deletion docs/src/interfaces.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ Connects the `Client` instance to the specified broker. There is a synchronous a
#### Arguments
**Required arguments:**
* **client**::Client: The client to connect to the broker.
* **connection**::MQTTConnection: The information for how the client connects to the broker.
* **connection**::Connection: The information for how the client connects to the broker.

use `MakeConnection` to get the client and the connection objects.

Expand Down
1 change: 1 addition & 0 deletions docs/src/utils.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
```@docs
MQTTClient.resolve
MQTTClient.topic_eq
MQTTClient.MockMQTTBroker
```
8 changes: 4 additions & 4 deletions examples/basic.jl
Original file line number Diff line number Diff line change
Expand Up @@ -6,22 +6,22 @@ payload = "Hello World!"

# Define the callback for receiving messages.
function on_msg(topic, payload)
println("Received message topic: [", topic, "] payload: [", String(payload), "]")
return println("Received message topic: [", topic, "] payload: [", String(payload), "]")
end

# Instantiate a client.
client, connection = MakeConnection(broker,1883)
client, connection = MakeConnection(broker, 1883)

connect(client, connection)
println("connected to $client at $(connection.protocol)")

# Subscribe to the topic.
subscribe(client, topic, on_msg, qos=QOS_2)
subscribe(client, topic, on_msg; qos=QOS_2)
println("subscribed to $topic")

sleep(0.5)

publish(client, topic, payload, qos=QOS_2)
publish(client, topic, payload; qos=QOS_2)
println("published $payload to $topic")

# Unsubscribe from the topic
Expand Down
72 changes: 33 additions & 39 deletions ext/PrecompileMQTT.jl
Original file line number Diff line number Diff line change
Expand Up @@ -8,47 +8,13 @@ using Sockets

using MQTTClient

precompile(Tuple{typeof(Core.kwcall), NamedTuple{(:qos,), Tuple{MQTTClient.QOS}}, typeof(MQTTClient.subscribe), MQTTClient.Client, String, Function})
precompile(Tuple{typeof(Core.kwcall), NamedTuple{(:qos,), Tuple{MQTTClient.QOS}}, typeof(MQTTClient.publish), MQTTClient.Client, String, String})

precompile(Tuple{typeof(Base.convert), Type{MQTTClient.Packet}, MQTTClient.Packet})
precompile(Tuple{typeof(Base.write), Base.PipeEndpoint, Array{UInt8, 1}})
precompile(Tuple{typeof(Base.read), Base.PipeEndpoint, Type{UInt8}})
precompile(Tuple{typeof(Base.indexed_iterate), Tuple{Nothing, Int64}, Int64})
precompile(Tuple{typeof(Base.read), Base.PipeEndpoint, Int64})
precompile(Tuple{typeof(Base.haskey), Base.Dict{UInt8, Function}, UInt8})
precompile(Tuple{typeof(Base.getindex), Base.Dict{UInt8, Function}, UInt8})
precompile(Tuple{typeof(Base.indexed_iterate), Tuple{Nothing, Int64}, Int64, Int64})
precompile(Tuple{typeof(Base.read), Sockets.TCPSocket, Int64})
precompile(Tuple{typeof(Base.write), Base.PipeEndpoint, UInt8})
precompile(Tuple{typeof(Base.fetch), Base.Channel{Any}})
precompile(Tuple{typeof(Base.iterate), UInt16})
precompile(Tuple{typeof(Base.something), MQTTClient.TrieNode{MQTTClient.FunctionCallback}, Nothing, Vararg{Any}})

precompile(Tuple{typeof(Sockets.connect), MQTTClient.Client, MQTTClient.MQTTConnection{MQTTClient.TCP}})
precompile(Tuple{typeof(Sockets.connect), Sockets.IPv6, Int64})
precompile(Tuple{typeof(Sockets.connect), MQTTClient.Client, MQTTClient.MQTTConnection{MQTTClient.UDS}})
precompile(Tuple{typeof(Sockets.connect), String})

precompile(Tuple{typeof(MQTTClient.write_len), Sockets.TCPSocket, Int64})
precompile(Tuple{typeof(MQTTClient.read_len), Sockets.TCPSocket})
precompile(Tuple{typeof(MQTTClient.write_packet), MQTTClient.Client, UInt8, String, Vararg{Any}})
precompile(Tuple{typeof(MQTTClient.mqtt_write), Base.GenericIOBuffer{Array{UInt8, 1}}, UInt8})
precompile(Tuple{typeof(MQTTClient.write_len), Base.PipeEndpoint, Int64})
precompile(Tuple{typeof(MQTTClient.read_len), Base.PipeEndpoint})
precompile(Tuple{typeof(MQTTClient.mqtt_write), Base.GenericIOBuffer{Array{UInt8, 1}}, MQTTClient.QOS})

precompile(Tuple{Type{MQTTClient.Packet}, UInt8, Tuple{}})
precompile(Tuple{Type{NamedTuple{(:qos,), T} where T<:Tuple}, Tuple{MQTTClient.QOS}})


# Precompiling the package like this provides a slower initial load of the package but faster code execution.
# based on tests this precompile step reduces compilation at runtime by ~25% and decreases first execution time by ~10%.
@setup_workload begin
# Putting some things in `@setup_workload` instead of `@compile_workload` can reduce the size of the
# precompile file and potentially make loading faster.

cb(t,p) = nothing
cb(t, p) = nothing
topic = "foo"
payload = "bar"

Expand All @@ -70,7 +36,11 @@ precompile(Tuple{Type{NamedTuple{(:qos,), T} where T<:Tuple}, Tuple{MQTTClient.Q

message = MQTTClient.Message(false, UInt8(MQTTClient.QOS_0), false, topic, payload)
optional = message.qos == 0x00 ? () : (0)
cmd = MQTTClient.PUBLISH | ((message.dup & 0x1) << 3) | (message.qos << 1) | message.retain
cmd =
MQTTClient.PUBLISH |
((message.dup & 0x1) << 3) |
(message.qos << 1) |
message.retain
packet = MQTTClient.Packet(cmd, [message.topic, optional..., message.payload])
buffer = PipeBuffer()
for i in packet.data
Expand Down Expand Up @@ -104,7 +74,6 @@ precompile(Tuple{Type{NamedTuple{(:qos,), T} where T<:Tuple}, Tuple{MQTTClient.Q
MQTTClient.handle_pubrel(c, s, cmd, flags)
p = take!(c.write_packets)


# handle_suback
c = MQTTClient.Client()
s = IOBuffer()
Expand All @@ -130,14 +99,39 @@ precompile(Tuple{Type{NamedTuple{(:qos,), T} where T<:Tuple}, Tuple{MQTTClient.Q
## Interfaces:
# subscribe
c = MQTTClient.Client()
future = MQTTClient.subscribe_async(c, topic, cb, qos=MQTTClient.QOS_2)
future = MQTTClient.subscribe_async(c, topic, cb; qos=MQTTClient.QOS_2)

# unsubscribe
c = MQTTClient.Client()
c = MQTTClient.Client()
insert!(c.on_msg, topic, cb)
@atomicswap c.last_id = 0x0
future = unsubscribe_async(c, topic)

## TCP Basic Run
server = MQTTClient.MockMQTTBroker(ip"127.0.0.1", 1889)
client, conn = MakeConnection(ip"127.0.0.1", 1889)

connect(client, conn)

subscribe(client, "foo/bar", cb)
publish(client, "bar/foo", "baz"; qos=QOS_2)
unsubscribe(client, "foo/bar")

disconnect(client)
close(server)

## UDS Basic Run
server = MQTTClient.MockMQTTBroker("/tmp/testmqtt.sock")
client, conn = MakeConnection("/tmp/testmqtt.sock")

connect(client, conn)

subscribe(client, "foo/bar", cb)
publish(client, "bar/foo", "baz")
unsubscribe(client, "foo/bar")

disconnect(client)
close(server)
end
end

Expand Down
12 changes: 5 additions & 7 deletions src/MQTTClient.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,12 @@ module MQTTClient

using Distributed: Future, myid, remotecall, RemoteChannel
using Sockets: TCPSocket, IPAddr, PipeServer, getaddrinfo
import Sockets: connect
import Sockets: connect, listen, accept
using Random: randstring
import Base: ReentrantLock, lock, unlock, convert, PipeEndpoint, fetch, show
import Base: @atomic, @atomicreplace, @atomicswap, Ref, RefValue, isready
using Base.Threads


include("utils.jl")
include("internals.jl")
include("topic.jl")
Expand All @@ -17,10 +16,10 @@ include("connection.jl")
include("handlers.jl")
include("interface.jl")

export
MakeConnection,
export MakeConnection,
Configuration,
Client,
MQTTConnection,
Connection,
IOConnection,
MQTTException,
User,
Expand All @@ -35,6 +34,5 @@ export
unsubscribe,
publish_async,
publish,
disconnect,
MQTT_ERR_INVAL
disconnect
end
Loading

2 comments on commit 6fcc30f

@NickMcSweeney
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@JuliaRegistrator register

Release notes:

Improved Testing and CI.

Changes

  • created mock broker
  • update precomp ext using mock broker
  • update tests using mock broker
  • update ci to auto format with blue style
  • changed MQTTConnection to Connection and made it a struct.
    • MakeConnection behaves the same

@JuliaRegistrator
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Registration pull request created: JuliaRegistries/General/107880

Tagging

After the above pull request is merged, it is recommended that a tag is created on this repository for the registered package version.

This will be done automatically if the Julia TagBot GitHub Action is installed, or can be done manually through the github interface, or via:

git tag -a v0.3.1 -m "<description of version>" 6fcc30ff7e54cd7443373d958fbf5954c4d79204
git push origin v0.3.1

Please sign in to comment.