Skip to content
Open
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
16 changes: 15 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,21 @@ Using Alpine Linux? Check out the [docs](https://github.com/Blizzard/node-rdkafk

### Windows

Windows build **is not** compiled from `librdkafka` source but it is rather linked against the appropriate version of [NuGet librdkafka.redist](https://www.nuget.org/packages/librdkafka.redist/) static binary that gets downloaded from `https://globalcdn.nuget.org/packages/librdkafka.redist.2.12.0.nupkg` during installation. This download link can be changed using the environment variable `NODE_RDKAFKA_NUGET_BASE_URL` that defaults to `https://globalcdn.nuget.org/packages/` when it's no set.
Windows build **is not** compiled from `librdkafka` source but it is rather
linked against the appropriate version of
[NuGet librdkafka.redist](https://www.nuget.org/packages/librdkafka.redist/)
static binary that gets downloaded from
`https://globalcdn.nuget.org/packages/librdkafka.redist.2.12.0.nupkg` during
installation. This download link can be changed using the environment variable
`NODE_RDKAFKA_NUGET_BASE_URL`, which defaults to
`https://globalcdn.nuget.org/packages/` when it is not set.

For private repositories, set `NODE_RDKAFKA_NUGET_HEADERS` to a JSON object of
HTTP request headers. This supports the authentication scheme required by the
repository, for example `{"Authorization":"Basic <base64-credentials>"}`,
`{"Authorization":"Bearer <token>"}`, or
`{"X-JFrog-Art-Api":"<api-key>"}`. Basic authentication credentials must be
Base64-encoded in the standard `username:password` format.

Requirements:
* [node-gyp for Windows](https://github.com/nodejs/node-gyp#on-windows)
Expand Down
131 changes: 76 additions & 55 deletions deps/windows-install.py
Original file line number Diff line number Diff line change
@@ -1,73 +1,94 @@
librdkafkaVersion = ''
# read librdkafka version from package.json
import errno
import glob
import json
import os
import glob
import shutil
import ssl
import zipfile

with open('../package.json') as f:
librdkafkaVersion = json.load(f)['librdkafka']
librdkafkaWinSufix = '7' if librdkafkaVersion == '0.11.5' else '';

depsPrecompiledDir = '../deps/precompiled'
depsIncludeDir = '../deps/include'
buildReleaseDir = 'Release'

# alternative: 'https://api.nuget.org/v3-flatcontainer/librdkafka.redist/{}/librdkafka.redist.{}.nupkg'.format(librdkafkaVersion, librdkafkaVersion)
env_dist = os.environ
downloadBaseUrl = env_dist['NODE_RDKAFKA_NUGET_BASE_URL'] if 'NODE_RDKAFKA_NUGET_BASE_URL' in env_dist else 'https://globalcdn.nuget.org/packages/'
librdkafkaNugetUrl = downloadBaseUrl + 'librdkafka.redist.{}.nupkg'.format(librdkafkaVersion)
print('download librdkafka form ' + librdkafkaNugetUrl)
outputDir = 'librdkafka.redist'
outputFile = outputDir + '.zip'
dllPath = outputDir + '/runtimes/win{}-x64/native'.format(librdkafkaWinSufix)
libPath = outputDir + '/build/native/lib/win{}/x64/win{}-x64-Release/v142'.format(librdkafkaWinSufix, librdkafkaWinSufix)
includePath = outputDir + '/build/native/include/librdkafka'

# download librdkafka from nuget
try:
# For Python 3.0 and later
from urllib.request import urlopen
from urllib.request import Request, urlopen
except ImportError:
# Fall back to Python 2's urllib2
from urllib2 import urlopen
import ssl
from urllib2 import Request, urlopen


def createdir(dir):
try:
os.makedirs(dir)
except OSError as e:
if errno.EEXIST != e.errno:
raise

filedata = urlopen(librdkafkaNugetUrl, context=ssl._create_unverified_context())

datatowrite = filedata.read()
with open(outputFile, 'wb') as f:
def createNugetRequest(url, environ):
headers = json.loads(environ.get('NODE_RDKAFKA_NUGET_HEADERS', '{}'))
if not isinstance(headers, dict):
raise ValueError('NODE_RDKAFKA_NUGET_HEADERS must be a JSON object')
return Request(url, headers=headers)


def main():
# read librdkafka version from package.json
with open('../package.json') as f:
librdkafkaVersion = json.load(f)['librdkafka']
librdkafkaWinSufix = '7' if librdkafkaVersion == '0.11.5' else ''

depsPrecompiledDir = '../deps/precompiled'
depsIncludeDir = '../deps/include'
buildReleaseDir = 'Release'

env_dist = os.environ
downloadBaseUrl = env_dist.get(
'NODE_RDKAFKA_NUGET_BASE_URL',
'https://globalcdn.nuget.org/packages/'
)
packageName = 'librdkafka.redist.{}.nupkg'.format(librdkafkaVersion)
librdkafkaNugetUrl = downloadBaseUrl + packageName
print('download librdkafka from ' + librdkafkaNugetUrl)
outputDir = 'librdkafka.redist'
outputFile = outputDir + '.zip'
dllPath = outputDir + '/runtimes/win{}-x64/native'.format(
librdkafkaWinSufix
)
libPath = outputDir + '/build/native/lib/win{}/x64/' \
'win{}-x64-Release/v142'.format(
librdkafkaWinSufix, librdkafkaWinSufix
)
includePath = outputDir + '/build/native/include/librdkafka'

# download librdkafka from nuget
request = createNugetRequest(librdkafkaNugetUrl, env_dist)
filedata = urlopen(request, context=ssl._create_unverified_context())

datatowrite = filedata.read()
with open(outputFile, 'wb') as f:
f.write(datatowrite)

# extract package
import zipfile
zip_ref = zipfile.ZipFile(outputFile, 'r')
zip_ref.extractall(outputDir)
zip_ref.close()
# extract package
zip_ref = zipfile.ZipFile(outputFile, 'r')
zip_ref.extractall(outputDir)
zip_ref.close()

# copy files
import shutil, os, errno
createdir(depsPrecompiledDir)
createdir(depsIncludeDir)
createdir(buildReleaseDir)

def createdir(dir):
try:
os.makedirs(dir)
except OSError as e:
if errno.EEXIST != e.errno:
raise
shutil.copy2(libPath + '/librdkafka.lib', depsPrecompiledDir)
shutil.copy2(libPath + '/librdkafkacpp.lib', depsPrecompiledDir)

createdir(depsPrecompiledDir)
createdir(depsIncludeDir)
createdir(buildReleaseDir)
shutil.copy2(includePath + '/rdkafka.h', depsIncludeDir)
shutil.copy2(includePath + '/rdkafkacpp.h', depsIncludeDir)

shutil.copy2(libPath + '/librdkafka.lib', depsPrecompiledDir)
shutil.copy2(libPath + '/librdkafkacpp.lib', depsPrecompiledDir)
# copy all the required dlls
for filename in glob.glob(os.path.join(dllPath, '*.dll')):
shutil.copy2(filename, buildReleaseDir)

shutil.copy2(includePath + '/rdkafka.h', depsIncludeDir)
shutil.copy2(includePath + '/rdkafkacpp.h', depsIncludeDir)
# clean up
os.remove(outputFile)
shutil.rmtree(outputDir)

# copy all the required dlls
for filename in glob.glob(os.path.join(dllPath, '*.dll')):
shutil.copy2(filename, buildReleaseDir)

# clean up
os.remove(outputFile)
shutil.rmtree(outputDir)
if __name__ == '__main__':
main()
60 changes: 60 additions & 0 deletions deps/windows-install.spec.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import base64
import importlib.util
import os
import unittest


SCRIPT_PATH = os.path.join(os.path.dirname(__file__), 'windows-install.py')
SPEC = importlib.util.spec_from_file_location('windows_install', SCRIPT_PATH)
WINDOWS_INSTALL = importlib.util.module_from_spec(SPEC)
SPEC.loader.exec_module(WINDOWS_INSTALL)


class CreateNugetRequestTest(unittest.TestCase):
def test_creates_request_without_headers(self):
request = WINDOWS_INSTALL.createNugetRequest(
'https://example.test/package.nupkg', {}
)

self.assertEqual(request.header_items(), [])

def test_adds_configured_authentication_headers(self):
environ = {
'NODE_RDKAFKA_NUGET_HEADERS': (
'{"Authorization":"Bearer token","X-Api-Key":"secret"}'
)
}

request = WINDOWS_INSTALL.createNugetRequest(
'https://example.test/package.nupkg', environ
)

self.assertEqual(request.get_header('Authorization'), 'Bearer token')
self.assertEqual(request.get_header('X-api-key'), 'secret')

def test_adds_base64_encoded_basic_authentication_header(self):
credentials = base64.b64encode(b'user:password').decode('ascii')
authorization = 'Basic ' + credentials
environ = {
'NODE_RDKAFKA_NUGET_HEADERS': (
'{"Authorization":"' + authorization + '"}'
)
}

request = WINDOWS_INSTALL.createNugetRequest(
'https://example.test/package.nupkg', environ
)

self.assertEqual(request.get_header('Authorization'), authorization)

def test_rejects_non_object_headers(self):
environ = {'NODE_RDKAFKA_NUGET_HEADERS': '["Authorization"]'}

with self.assertRaisesRegex(ValueError, 'must be a JSON object'):
WINDOWS_INSTALL.createNugetRequest(
'https://example.test/package.nupkg', environ
)


if __name__ == '__main__':
unittest.main()