Skip to content
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
38 changes: 29 additions & 9 deletions .github/workflows/build.yml → .github/workflows/publish.yml
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
name: Build
name: Publish
on:
push:
branches:
- main
- beta
workflow_dispatch:
release:
types: [published]
permissions:
contents: read
concurrency:
group: build-${{ github.ref }}
cancel-in-progress: false
jobs:
prebuild:
if: github.repository == 'DragonWork/bindings-cpp'
strategy:
matrix:
include:
Expand Down Expand Up @@ -107,6 +109,9 @@ jobs:
needs: prebuild
name: Release
runs-on: ubuntu-latest
permissions:
contents: read
id-token: write
steps:
- uses: actions/checkout@v4
- uses: actions/download-artifact@v4
Expand All @@ -116,10 +121,25 @@ jobs:
path: prebuilds
- uses: actions/setup-node@v4
with:
node-version: 20
node-version: 24
registry-url: https://registry.npmjs.org
- name: Check release version
if: github.event_name == 'release'
env:
RELEASE_TAG: ${{ github.event.release.tag_name }}
run: node -e "if (process.env.RELEASE_TAG !== 'v' + require('./package.json').version) throw new Error('Release tag must match package.json version')"
- run: npm ci
- run: npm run build
- run: npm run semantic-release
- run: npm run typecheck
- run: npm test
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
NODE_OPTIONS: --no-experimental-strip-types
- run: npm pack
- uses: actions/upload-artifact@v4
with:
name: npm-package
path: dragonwork-serialport-bindings-cpp-*.tgz
if-no-files-found: error
- name: Publish to npm
if: github.event_name == 'release'
run: npm publish dragonwork-serialport-bindings-cpp-*.tgz --access public --tag latest
28 changes: 27 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,30 @@
# @serialport/bindings-cpp
# @dragonwork/serialport-bindings-cpp

Temporary fork of `@serialport/bindings-cpp` with the native callback fixes from
[serialport/bindings-cpp#243](https://github.com/serialport/bindings-cpp/pull/243).
The upstream API is unchanged. Use an npm alias to keep existing imports:

```json
"@serialport/bindings-cpp": "npm:@dragonwork/serialport-bindings-cpp@13.0.1-patch.1"
```

### Publishing this fork

The **Publish** workflow rebuilds upstream's native prebuild matrix and packs it
with the compiled JavaScript. Running it manually only uploads the `npm-package`
artifact; it does not publish.

For the first publication, own the `@dragonwork` scope on npm, run the workflow,
download and extract `npm-package`, then use `npm login` and
`npm publish dragonwork-serialport-bindings-cpp-13.0.1-patch.1.tgz --access public --tag latest`.

In the npm package settings, add a trusted publisher for GitHub owner `DragonWork`,
repository `bindings-cpp`, workflow `publish.yml`, with direct `npm publish`
allowed. No npm token is needed in GitHub. Future GitHub releases publish through
OIDC; their tags must match `v` plus the version in `package.json` (also update
`package-lock.json`). Do not create a release for an already published version.

## Upstream documentation

[![Backers on Open Collective](https://opencollective.com/serialport/backers/badge.svg)](#backers)
[![Sponsors on Open Collective](https://opencollective.com/serialport/sponsors/badge.svg)](#sponsors)
Expand Down
8 changes: 4 additions & 4 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@serialport/bindings-cpp",
"name": "@dragonwork/serialport-bindings-cpp",
"description": "SerialPort Hardware bindings for node serialport written in c++",
"version": "0.0.0-development",
"version": "13.0.1-patch.1",
"main": "./dist/index.js",
"types": "./dist/index.d.ts",
"keywords": [
Expand Down Expand Up @@ -91,7 +91,7 @@
},
"repository": {
"type": "git",
"url": "https://github.com/serialport/bindings-cpp.git"
"url": "https://github.com/DragonWork/bindings-cpp.git"
},
"funding": "https://opencollective.com/serialport/donate",
"changelog": {
Expand Down
10 changes: 7 additions & 3 deletions src/poller.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@
#include <uv.h>
#include "./poller.h"

Poller::Poller (const Napi::CallbackInfo &info) : Napi::ObjectWrap<Poller>(info)
Poller::Poller (const Napi::CallbackInfo &info) : Napi::ObjectWrap<Poller>(info),
async_context(info.Env(), "serialport:Poller")
{
Napi::Env env = info.Env();
Napi::HandleScope scope(env);
Expand Down Expand Up @@ -81,13 +82,16 @@ void Poller::onData(uv_poll_t* handle, int status, int events) {
if (0 != status) {
// fprintf(stdout, "OnData Error status=%s events=%d\n", uv_strerror(status), events);
obj->_stop(); // doesn't matter if this errors
obj->callback.Call({Napi::Error::New(env, uv_strerror(status)).Value(), env.Undefined()});
obj->callback.MakeCallback(env.Global(),
{Napi::Error::New(env, uv_strerror(status)).Value(), env.Undefined()}, obj->async_context);
} else {
// fprintf(stdout, "OnData status=%d events=%d subscribed=%d\n", status, events, obj->events);
// remove triggered events from the poll
int newEvents = obj->events & ~events;
obj->poll(env, newEvents);
obj->callback.Call({env.Null(), Napi::Number::New(env, events)});
// uv_poll invokes us outside Node's callback scopes. MakeCallback drains
// nextTick and Promise continuations before the event loop waits again.
obj->callback.MakeCallback(env.Global(), {env.Null(), Napi::Number::New(env, events)}, obj->async_context);
}

}
Expand Down
1 change: 1 addition & 0 deletions src/poller.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ class Poller : public Napi::ObjectWrap<Poller> {
int fd;
uv_poll_t* poll_handle = nullptr;
Napi::FunctionReference callback;
Napi::AsyncContext async_context;
bool uv_poll_init_success = false;

// can this be read off of poll_handle?
Expand Down
14 changes: 8 additions & 6 deletions src/serialport_win.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -380,9 +380,9 @@ void EIO_AfterWrite(uv_async_t* req) {

v8::Local<v8::Value> argv[1];
if (baton->errorString[0]) {
baton->callback.Call({Napi::Error::New(env, baton->errorString).Value()});
baton->callback.MakeCallback(env.Global(), {Napi::Error::New(env, baton->errorString).Value()}, baton->async_context);
} else {
baton->callback.Call({env.Null()});
baton->callback.MakeCallback(env.Global(), {env.Null()}, baton->async_context);
}
baton->buffer.Reset();
delete baton;
Expand Down Expand Up @@ -414,7 +414,7 @@ Napi::Value Write(const Napi::CallbackInfo& info) {
return env.Null();
}

WriteBaton* baton = new WriteBaton();
WriteBaton* baton = new WriteBaton(env);
baton->callback = Napi::Persistent(info[2].As<Napi::Function>());
baton->fd = fd;
baton->buffer.Reset(buffer);
Expand Down Expand Up @@ -552,9 +552,11 @@ void EIO_AfterRead(uv_async_t* req) {
uv_close(reinterpret_cast<uv_handle_t*>(req), AsyncCloseCallback);

if (baton->errorString[0]) {
baton->callback.Call({Napi::Error::New(env, baton->errorString).Value(), env.Undefined()});
baton->callback.MakeCallback(env.Global(),
{Napi::Error::New(env, baton->errorString).Value(), env.Undefined()}, baton->async_context);
} else {
baton->callback.Call({env.Null(), Napi::Number::New(env, static_cast<int>(baton->bytesRead))});
baton->callback.MakeCallback(env.Global(),
{env.Null(), Napi::Number::New(env, static_cast<int>(baton->bytesRead))}, baton->async_context);
}
delete baton;
}
Expand Down Expand Up @@ -600,7 +602,7 @@ Napi::Value Read(const Napi::CallbackInfo& info) {
Napi::TypeError::New(env, "Fifth argument must be a function").ThrowAsJavaScriptException();
return env.Null();
}
ReadBaton* baton = new ReadBaton();
ReadBaton* baton = new ReadBaton(env);
baton->callback = Napi::Persistent(info[4].As<Napi::Function>());
baton->fd = fd;
baton->offset = offset;
Expand Down
6 changes: 4 additions & 2 deletions src/serialport_win.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ static inline HANDLE int2handle(int ptr) {
}

struct WriteBaton {
WriteBaton() : bufferData(), errorString() {}
explicit WriteBaton(Napi::Env env) : bufferData(), async_context(env, "serialport:Write"), errorString() {}
int fd = 0;
char* bufferData = nullptr;
size_t bufferLength = 0;
Expand All @@ -23,14 +23,15 @@ struct WriteBaton {
bool complete = false;
Napi::ObjectReference buffer;
Napi::FunctionReference callback;
Napi::AsyncContext async_context;
int result = 0;
char errorString[ERROR_STRING_SIZE];
};

Napi::Value Write(const Napi::CallbackInfo& info);

struct ReadBaton {
ReadBaton() : errorString() {}
explicit ReadBaton(Napi::Env env) : async_context(env, "serialport:Read"), errorString() {}
int fd = 0;
char* bufferData = nullptr;
size_t bufferLength = 0;
Expand All @@ -39,6 +40,7 @@ struct ReadBaton {
size_t offset = 0;
void* hThread = nullptr;
Napi::FunctionReference callback;
Napi::AsyncContext async_context;
bool complete = false;
char errorString[ERROR_STRING_SIZE];
};
Expand Down