feat: set up FFI
Signed-off-by: Sphericalkat <me@kat.bio>
This commit is contained in:
		
						commit
						a5b8aa83d6
					
				
							
								
								
									
										10
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,10 @@ | |||||||
|  | # https://dart.dev/guides/libraries/private-files | ||||||
|  | # Created by `dart pub` | ||||||
|  | .dart_tool/ | ||||||
|  | 
 | ||||||
|  | # Avoid committing pubspec.lock for library packages; see | ||||||
|  | # https://dart.dev/guides/libraries/private-files#pubspeclock. | ||||||
|  | pubspec.lock | ||||||
|  | 
 | ||||||
|  | # FVM Version Cache | ||||||
|  | .fvm/ | ||||||
							
								
								
									
										3
									
								
								.vscode/settings.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								.vscode/settings.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,3 @@ | |||||||
|  | { | ||||||
|  |   "dart.flutterSdkPath": ".fvm/versions/stable" | ||||||
|  | } | ||||||
							
								
								
									
										3
									
								
								CHANGELOG.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								CHANGELOG.md
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,3 @@ | |||||||
|  | ## 1.0.0 | ||||||
|  | 
 | ||||||
|  | - Initial version. | ||||||
							
								
								
									
										39
									
								
								README.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								README.md
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,39 @@ | |||||||
|  | <!--  | ||||||
|  | This README describes the package. If you publish this package to pub.dev, | ||||||
|  | this README's contents appear on the landing page for your package. | ||||||
|  | 
 | ||||||
|  | For information about how to write a good package README, see the guide for | ||||||
|  | [writing package pages](https://dart.dev/guides/libraries/writing-package-pages).  | ||||||
|  | 
 | ||||||
|  | For general information about developing packages, see the Dart guide for | ||||||
|  | [creating packages](https://dart.dev/guides/libraries/create-library-packages) | ||||||
|  | and the Flutter guide for | ||||||
|  | [developing packages and plugins](https://flutter.dev/developing-packages).  | ||||||
|  | --> | ||||||
|  | 
 | ||||||
|  | TODO: Put a short description of the package here that helps potential users | ||||||
|  | know whether this package might be useful for them. | ||||||
|  | 
 | ||||||
|  | ## Features | ||||||
|  | 
 | ||||||
|  | TODO: List what your package can do. Maybe include images, gifs, or videos. | ||||||
|  | 
 | ||||||
|  | ## Getting started | ||||||
|  | 
 | ||||||
|  | TODO: List prerequisites and provide or point to information on how to | ||||||
|  | start using the package. | ||||||
|  | 
 | ||||||
|  | ## Usage | ||||||
|  | 
 | ||||||
|  | TODO: Include short and useful examples for package users. Add longer examples | ||||||
|  | to `/example` folder.  | ||||||
|  | 
 | ||||||
|  | ```dart | ||||||
|  | const like = 'sample'; | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | ## Additional information | ||||||
|  | 
 | ||||||
|  | TODO: Tell users more about the package: where to find more information, how to  | ||||||
|  | contribute to the package, how to file issues, what response they can expect  | ||||||
|  | from the package authors, and more. | ||||||
							
								
								
									
										30
									
								
								analysis_options.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								analysis_options.yaml
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,30 @@ | |||||||
|  | # This file configures the static analysis results for your project (errors, | ||||||
|  | # warnings, and lints). | ||||||
|  | # | ||||||
|  | # This enables the 'recommended' set of lints from `package:lints`. | ||||||
|  | # This set helps identify many issues that may lead to problems when running | ||||||
|  | # or consuming Dart code, and enforces writing Dart using a single, idiomatic | ||||||
|  | # style and format. | ||||||
|  | # | ||||||
|  | # If you want a smaller set of lints you can change this to specify | ||||||
|  | # 'package:lints/core.yaml'. These are just the most critical lints | ||||||
|  | # (the recommended set includes the core lints). | ||||||
|  | # The core lints are also what is used by pub.dev for scoring packages. | ||||||
|  | 
 | ||||||
|  | include: package:lints/recommended.yaml | ||||||
|  | 
 | ||||||
|  | # Uncomment the following section to specify additional rules. | ||||||
|  | 
 | ||||||
|  | # linter: | ||||||
|  | #   rules: | ||||||
|  | #     - camel_case_types | ||||||
|  | 
 | ||||||
|  | # analyzer: | ||||||
|  | #   exclude: | ||||||
|  | #     - path/to/excluded/files/** | ||||||
|  | 
 | ||||||
|  | # For more information about the core and recommended set of lints, see | ||||||
|  | # https://dart.dev/go/core-lints | ||||||
|  | 
 | ||||||
|  | # For additional information about configuring this file, see | ||||||
|  | # https://dart.dev/guides/language/analysis-options | ||||||
							
								
								
									
										7
									
								
								example/readability_example.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								example/readability_example.dart
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,7 @@ | |||||||
|  | import 'package:readability/readability.dart'; | ||||||
|  | 
 | ||||||
|  | void main() { | ||||||
|  |   var parser = ReadabilityParser(); | ||||||
|  |   Article article = parser.parse('https://www.bbc.com/sport/football/articles/cl7y4z82z2do'); | ||||||
|  |   print(article.toString()); | ||||||
|  | } | ||||||
							
								
								
									
										9
									
								
								lib/readability.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								lib/readability.dart
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,9 @@ | |||||||
|  | /// Support for doing something awesome. | ||||||
|  | /// | ||||||
|  | /// More dartdocs go here. | ||||||
|  | library; | ||||||
|  | 
 | ||||||
|  | export 'src/readability_parser.dart'; | ||||||
|  | export 'src/article.dart'; | ||||||
|  | 
 | ||||||
|  | // TODO: Export any libraries intended for clients of this package. | ||||||
							
								
								
									
										33
									
								
								lib/src/article.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								lib/src/article.dart
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,33 @@ | |||||||
|  | 
 | ||||||
|  | class Article { | ||||||
|  |   final String? title; | ||||||
|  |   final String? author; | ||||||
|  |   final int length; | ||||||
|  |   final String? excerpt; | ||||||
|  |   final String? siteName; | ||||||
|  |   final String? imageUrl; | ||||||
|  |   final String? faviconUrl; | ||||||
|  |   final String? content; | ||||||
|  |   final String? textContent; | ||||||
|  |   final String? language; | ||||||
|  |   final String? publishedTime; | ||||||
|  | 
 | ||||||
|  |   Article({ | ||||||
|  |     required this.title, | ||||||
|  |     required this.author, | ||||||
|  |     required this.length, | ||||||
|  |     required this.excerpt, | ||||||
|  |     required this.siteName, | ||||||
|  |     required this.imageUrl, | ||||||
|  |     required this.faviconUrl, | ||||||
|  |     required this.content, | ||||||
|  |     required this.textContent, | ||||||
|  |     required this.language, | ||||||
|  |     required this.publishedTime, | ||||||
|  |   }); | ||||||
|  | 
 | ||||||
|  |   @override | ||||||
|  |   String toString() { | ||||||
|  |     return 'Article{title: $title,\n author: $author,\n length: $length,\n excerpt: $excerpt,\n siteName: $siteName,\n imageUrl: $imageUrl,\n faviconUrl: $faviconUrl,\n content: $content,\n textContent: $textContent,\n language: $language,\n publishedTime: $publishedTime}'; | ||||||
|  |   } | ||||||
|  | } | ||||||
							
								
								
									
										88
									
								
								lib/src/readability_parser.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										88
									
								
								lib/src/readability_parser.dart
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,88 @@ | |||||||
|  | import 'dart:ffi' as ffi; | ||||||
|  | import 'dart:ffi'; | ||||||
|  | import 'package:ffi/ffi.dart'; | ||||||
|  | import 'dart:io' show Platform; | ||||||
|  | 
 | ||||||
|  | import 'package:readability/src/article.dart'; | ||||||
|  | 
 | ||||||
|  | final class CArticle extends Struct { | ||||||
|  |   external Pointer<Utf8> title; | ||||||
|  |   external Pointer<Utf8> author; | ||||||
|  |   @Int32() | ||||||
|  |   external int length; | ||||||
|  |   external Pointer<Utf8> excerpt; | ||||||
|  |   external Pointer<Utf8> site_name; | ||||||
|  |   external Pointer<Utf8> image_url; | ||||||
|  |   external Pointer<Utf8> favicon_url; | ||||||
|  |   external Pointer<Utf8> content; | ||||||
|  |   external Pointer<Utf8> text_content; | ||||||
|  |   external Pointer<Utf8> language; | ||||||
|  |   external Pointer<Utf8> published_time; | ||||||
|  |   external Pointer<Utf8> err; | ||||||
|  | 
 | ||||||
|  |   @Int32() | ||||||
|  |   external int success; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | typedef ParseFunc = CArticle Function(Pointer<Utf8> url); | ||||||
|  | typedef ParseDart = CArticle Function(Pointer<Utf8> url); | ||||||
|  | 
 | ||||||
|  | typedef FreeArticleFunc = Void Function(CArticle article); | ||||||
|  | typedef FreeArticleDart = void Function(CArticle article); | ||||||
|  | 
 | ||||||
|  | class ReadabilityParser { | ||||||
|  |   late final DynamicLibrary _lib; | ||||||
|  |   late final ParseDart _parse; | ||||||
|  |   late final FreeArticleDart _freeArticle; | ||||||
|  | 
 | ||||||
|  |   ReadabilityParser() { | ||||||
|  |     _lib = ffi.DynamicLibrary.open(_getDylibPath()); | ||||||
|  |     _parse = _lib.lookupFunction<ParseFunc, ParseDart>('Parse'); | ||||||
|  |     _freeArticle = | ||||||
|  |         _lib.lookupFunction<FreeArticleFunc, FreeArticleDart>('FreeArticle'); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   Article parse(String url) { | ||||||
|  |     // Convert the URL to a native string. | ||||||
|  |     final urlPtr = url.toNativeUtf8(); | ||||||
|  | 
 | ||||||
|  |     // Call the native function. | ||||||
|  |     final article = _parse(urlPtr); | ||||||
|  | 
 | ||||||
|  |     // Free the memory allocated for the URL. | ||||||
|  |     malloc.free(urlPtr); | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  |     // Convert the native article to a Dart article. | ||||||
|  |     final articleDart = Article( | ||||||
|  |       title: article.title == nullptr ? null : article.title.toDartString(), | ||||||
|  |       author: article.author == nullptr ? null : article.author.toDartString(), | ||||||
|  |       length: article.length, | ||||||
|  |       excerpt: article.excerpt == nullptr ? null : article.excerpt.toDartString(), | ||||||
|  |       siteName: article.site_name == nullptr ? null : article.site_name.toDartString(), | ||||||
|  |       imageUrl: article.image_url == nullptr ? null : article.image_url.toDartString(), | ||||||
|  |       faviconUrl: article.favicon_url == nullptr ? null : article.favicon_url.toDartString(), | ||||||
|  |       content: article.content == nullptr ? null : article.content.toDartString(), | ||||||
|  |       textContent: article.text_content == nullptr ? null : article.text_content.toDartString(), | ||||||
|  |       language: article.language == nullptr ? null : article.language.toDartString(), | ||||||
|  |       publishedTime: article.published_time == nullptr ? null : article.published_time.toDartString(), | ||||||
|  |     ); | ||||||
|  | 
 | ||||||
|  |     // Free the memory allocated for the article. | ||||||
|  |     _freeArticle(article); | ||||||
|  | 
 | ||||||
|  |     return articleDart; | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | String _getDylibPath() { | ||||||
|  |   if (Platform.isWindows) { | ||||||
|  |     return 'native/windows/x64/readability.dll'; | ||||||
|  |   } else if (Platform.isMacOS) { | ||||||
|  |     return 'native/macos/x64/readability.dylib'; | ||||||
|  |   } else if (Platform.isLinux) { | ||||||
|  |     return 'native/linux/x86-64/libreadability.so'; | ||||||
|  |   } else { | ||||||
|  |     throw UnsupportedError('This platform is not supported.'); | ||||||
|  |   } | ||||||
|  | } | ||||||
							
								
								
									
										103
									
								
								native/linux/x86-64/libreadability.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										103
									
								
								native/linux/x86-64/libreadability.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,103 @@ | |||||||
|  | /* Code generated by cmd/cgo; DO NOT EDIT. */ | ||||||
|  | 
 | ||||||
|  | /* package command-line-arguments */ | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | #line 1 "cgo-builtin-export-prolog" | ||||||
|  | 
 | ||||||
|  | #include <stddef.h> | ||||||
|  | 
 | ||||||
|  | #ifndef GO_CGO_EXPORT_PROLOGUE_H | ||||||
|  | #define GO_CGO_EXPORT_PROLOGUE_H | ||||||
|  | 
 | ||||||
|  | #ifndef GO_CGO_GOSTRING_TYPEDEF | ||||||
|  | typedef struct { const char *p; ptrdiff_t n; } _GoString_; | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | /* Start of preamble from import "C" comments.  */ | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | #line 3 "main.go" | ||||||
|  | 
 | ||||||
|  | #include <stdlib.h> | ||||||
|  | 
 | ||||||
|  | typedef struct { | ||||||
|  | 	char* title; | ||||||
|  | 	char* author; | ||||||
|  | 	int length; | ||||||
|  | 	char* excerpt; | ||||||
|  | 	char* site_name; | ||||||
|  | 	char* image_url; | ||||||
|  | 	char* favicon_url; | ||||||
|  | 	char* content; // HTML content
 | ||||||
|  | 	char* text_content; // text content
 | ||||||
|  | 	char* language; | ||||||
|  | 	char* published_time; | ||||||
|  | 	char* err; | ||||||
|  | 	int success; | ||||||
|  | } CArticle; | ||||||
|  | 
 | ||||||
|  | #line 1 "cgo-generated-wrapper" | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | /* End of preamble from import "C" comments.  */ | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | /* Start of boilerplate cgo prologue.  */ | ||||||
|  | #line 1 "cgo-gcc-export-header-prolog" | ||||||
|  | 
 | ||||||
|  | #ifndef GO_CGO_PROLOGUE_H | ||||||
|  | #define GO_CGO_PROLOGUE_H | ||||||
|  | 
 | ||||||
|  | typedef signed char GoInt8; | ||||||
|  | typedef unsigned char GoUint8; | ||||||
|  | typedef short GoInt16; | ||||||
|  | typedef unsigned short GoUint16; | ||||||
|  | typedef int GoInt32; | ||||||
|  | typedef unsigned int GoUint32; | ||||||
|  | typedef long long GoInt64; | ||||||
|  | typedef unsigned long long GoUint64; | ||||||
|  | typedef GoInt64 GoInt; | ||||||
|  | typedef GoUint64 GoUint; | ||||||
|  | typedef size_t GoUintptr; | ||||||
|  | typedef float GoFloat32; | ||||||
|  | typedef double GoFloat64; | ||||||
|  | #ifdef _MSC_VER | ||||||
|  | #include <complex.h> | ||||||
|  | typedef _Fcomplex GoComplex64; | ||||||
|  | typedef _Dcomplex GoComplex128; | ||||||
|  | #else | ||||||
|  | typedef float _Complex GoComplex64; | ||||||
|  | typedef double _Complex GoComplex128; | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | /*
 | ||||||
|  |   static assertion to make sure the file is being used on architecture | ||||||
|  |   at least with matching size of GoInt. | ||||||
|  | */ | ||||||
|  | typedef char _check_for_64_bit_pointer_matching_GoInt[sizeof(void*)==64/8 ? 1:-1]; | ||||||
|  | 
 | ||||||
|  | #ifndef GO_CGO_GOSTRING_TYPEDEF | ||||||
|  | typedef _GoString_ GoString; | ||||||
|  | #endif | ||||||
|  | typedef void *GoMap; | ||||||
|  | typedef void *GoChan; | ||||||
|  | typedef struct { void *t; void *v; } GoInterface; | ||||||
|  | typedef struct { void *data; GoInt len; GoInt cap; } GoSlice; | ||||||
|  | 
 | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | /* End of boilerplate cgo prologue.  */ | ||||||
|  | 
 | ||||||
|  | #ifdef __cplusplus | ||||||
|  | extern "C" { | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | extern CArticle Parse(char* url); | ||||||
|  | extern void FreeArticle(CArticle article); | ||||||
|  | 
 | ||||||
|  | #ifdef __cplusplus | ||||||
|  | } | ||||||
|  | #endif | ||||||
							
								
								
									
										
											BIN
										
									
								
								native/linux/x86-64/libreadability.so
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								native/linux/x86-64/libreadability.so
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										16
									
								
								pubspec.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								pubspec.yaml
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,16 @@ | |||||||
|  | name: readability | ||||||
|  | description: A starting point for Dart libraries or applications. | ||||||
|  | version: 1.0.0 | ||||||
|  | # repository: https://github.com/my_org/my_repo | ||||||
|  | 
 | ||||||
|  | environment: | ||||||
|  |   sdk: ^3.4.3 | ||||||
|  | 
 | ||||||
|  | # Add regular dependencies here. | ||||||
|  | dependencies: | ||||||
|  |   ffi: ^2.1.2 | ||||||
|  |   # path: ^1.8.0 | ||||||
|  | 
 | ||||||
|  | dev_dependencies: | ||||||
|  |   lints: ^3.0.0 | ||||||
|  |   test: ^1.24.0 | ||||||
							
								
								
									
										17
									
								
								test/readability_test.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								test/readability_test.dart
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,17 @@ | |||||||
|  | import 'package:readability/readability.dart'; | ||||||
|  | import 'package:test/test.dart'; | ||||||
|  | 
 | ||||||
|  | void main() { | ||||||
|  |   group('A group of tests', () { | ||||||
|  |     final ReadabilityParser parser = ReadabilityParser(); | ||||||
|  | 
 | ||||||
|  |     setUp(() { | ||||||
|  |       // Additional setup goes here. | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  |     test('First Test', () { | ||||||
|  |       final Article article = parser.parse('https://www.bbc.com/sport/football/articles/cl7y4z82z2do'); | ||||||
|  |       expect(article.title, isNotNull); | ||||||
|  |     }); | ||||||
|  |   }); | ||||||
|  | } | ||||||
		Loading…
	
		Reference in New Issue
	
	Block a user