How to get MAC-address in Rust? - network-programming

How to obtain hwaddr of first ethernet card?
And how to list all interfaces?

On Unix-like OS, /sys/class/net/ contains the symlinks to the available interfaces on your machine and the MAC address of an interface is written in a file like /sys/class/net/eth0/address
On windows, I guess you have to parse the output of an external command like ipconfig to pick up your desired information.
A demo:
use std::fs;
use std::io::Read;
use std::path::Path;
fn main() {
let net = Path::new("/sys/class/net");
let entry = fs::read_dir(net).expect("Error");
// a bit cubersome :/
let ifaces = entry.filter_map(|p| p.ok())
.map(|p| p.path().file_name().expect("Error").to_os_string())
.filter_map(|s| s.into_string().ok())
.collect::<Vec<String>>();
println!("Available interfaces: {:?}", ifaces);
let iface = net.join(ifaces[0].as_str()).join("address");
let mut f = fs::File::open(iface).expect("Failed");
let mut macaddr = String::new();
f.read_to_string(&mut macaddr).expect("Error");
println!("MAC address: {}", macaddr);
}

Related

Deserializing to enum option in F#

A couple days ago, I posted a question about deserialization with enums in F#.
The question is here: Deserialization in F# vs. C#
The answer pointed to some code written by Isaac Abraham, at: https://gist.github.com/isaacabraham/ba679f285bfd15d2f53e
However I am facing another problem:
If the object to deserialize to has an object of type 'enum option', the deserialization will fail, whereas it'll work if the type is just 'enum'.
A minimal example:
type TestType =
| A = 0
| B = 1
type TestObjectA =
{
test : TestType
}
type TestObjectB =
{
test : TestType option
}
let x = "{\"test\":\"A\"}"
let TestA = Deserialize<TestObjectA> x // will work
let TestB = Deserialize<TestObjectB> x // will fail
and the large deserialization code is at: https://pastebin.com/95JZLa6j
I put the whole code in a fiddle: https://dotnetfiddle.net/0Vc0Rh
but it can't be run from there since the F# version they support will not accept the 'object' keyword.
So, my question is: why can't I use the option type on an enum, but it works on other types? As a side note, since I'm quite new to F#, I'm not fully understanding Isaac's code, although I spent some time going through it and trying to troubleshoot it.
My understanding is that this line:
|> Seq.map (fun (value, propertyInfo) -> Convert.ChangeType(value, propertyInfo.PropertyType))
will try to convert the type to the right enum, but not to the enum option.
As a bonus question, is there a working solution that does full idiomatic deserialization with enums? (without going through null types)
open System.IO
type TestType =
| A = 0
| B = 1
type TestObjectB =
{
test : TestType option
}
let jsonSerializeToString obj =
use writer = new StringWriter()
let ser = new Newtonsoft.Json.JsonSerializer()
ser.Formatting <- Newtonsoft.Json.Formatting.Indented
ser.Serialize(writer, obj)
writer.ToString()
let jsonDeserializeFromString str =
Newtonsoft.Json.JsonConvert.DeserializeObject<TestObjectB>(str)
let Test obj =
let str = jsonSerializeToString obj
let obj' = jsonDeserializeFromString str
obj'
[<EntryPoint>]
let main argv =
{ test = Some TestType.B } |> Test |> ignore
{ test = None } |> Test |> ignore
0
Note: if you need to serialize a large collection of objects, then stream them to a file instead of an in-memory string to avoid an OutOfMemoryException. Like use writer = File.CreateText(filePath).
As a bonus question, is there a working solution that does full
idiomatic deserialization with enums?
I use the Microsoft.FsharpLu.Json package in production and find it works quite well for serializing and deserializing between "plain" javascript and idiomatic F#. Note Microsoft.FsharpLu.Json relies on Newtonsoft.Json under the hood.
Below is an example with your types and your test string, using Expecto for tests.
namespace FsharpLuJsonTest
open Newtonsoft.Json
open Microsoft.FSharpLu.Json
open Expecto
open Expecto.Flip
// Setup for FSharpLu.Json
type JsonSettings =
static member settings =
let s = JsonSerializerSettings(
NullValueHandling = NullValueHandling.Ignore,
MissingMemberHandling = MissingMemberHandling.Ignore)
s.Converters.Add(CompactUnionJsonConverter())
s
static member formatting = Formatting.None
type JsonSerializer = With<JsonSettings>
// Your example
type TestType =
| A = 0
| B = 1
type TestObjectA = { test : TestType }
type TestObjectB = { test : TestType option }
module Tests =
let x = """{"test":"A"}"""
[<Tests>]
let tests =
testList "Deserialization Tests" [
testCase "To TestObjectA" <| fun _ ->
JsonSerializer.deserialize x
|> Expect.equal "" { TestObjectA.test = TestType.A }
testCase "To TestObjectB" <| fun _ ->
JsonSerializer.deserialize x
|> Expect.equal "" { TestObjectB.test = Some TestType.A }
]
module Main =
[<EntryPoint>]
let main args =
runTestsInAssembly defaultConfig args
As you can see FsharpLu.Json supports Discriminated Unions and option types out of the box in the way you prefer. FsharpLu.Json is a less flexible solution than some others like Chiron (which allow for much more customisation) but I tend to prefer the opinionated approach of FsharpLu.Json.
I haven't used it personally, but the new FSharp.SystemText.Json library with the JsonUnionEncoding.ExternalTag setting should work roughly the same way FsharpLu.Json does. That library uses Microsoft's new System.Text.Json library under the hood rather than Newtonsoft.Json.

Type annotation for using a F# TypeProvider type e.g. FSharp.Data.JsonProvider<...>.DomainTypes.Url

I'm using the FSharp.Data.JsonProvider to read Twitter Tweets.
Playing with this sample code
https://github.com/tpetricek/Documents/tree/master/Samples/Twitter.API
I want to expand the urls in the tweet with
let expandUrl (txt:string) (url:Search.DomainTypes<...>.DomainTypes.Url) =
txt.Replace( url.Url, url.ExpandedUrl )
This results in Error:
Lookup on object of indeterminate type based on information prior to this program point.
A type annotation may be needed prior to this program point to constrain the type of the object.
My problem is how to define the TypeProvider Type for url in the expandUrl function above?
The type inferance shows me this
val urls : FSharp.Data.JsonProvider<...>.DomainTypes.Url []
but this is not accepted in the type declaration. I assume "<...>" is not F# synatx.
How to do a type annotation for using a TypeProvider type e.g. FSharp.Data.JsonProvider<...>.DomainTypes.Url ?
Here is the complete code snippet:
open TwitterAPI // github.com/tpetricek/Documents/tree/master/Samples/Twitter.API
let twitter = TwitterAPI.TwitterContext( _consumerKey, _consumerSecret, _accessToken, _accessTokenSecret )
let query = "water"
let ts = Twitter.Search.Tweets(twitter, Utils.urlEncode query, count=100)
let ret =
[ for x in ts.Statuses do
// val urls : FSharp.Data.JsonProvider<...>.DomainTypes.Url []
let urls = x.Entities.Urls
// fully declarated to help the type inference at expandUrl
let replace (txt:string) (oldValue:string) (newValue:string) =
txt.Replace( oldValue, newValue)
// Error:
// Lookup on object of indeterminate type based on information prior to this program point.
// A type annotation may be needed prior to this program point to constrain the type of the object.
// This may allow the lookup to be resolved.
let expandUrl (txt:string) (url:FSharp.Data.JsonProvider<_>.DomainTypes.Url) =
replace txt url.Url url.ExpandedUrl
let textWithExpandedUrls = Array.fold expandUrl x.Text urls
yield textWithExpandedUrls
]
When you call Twitter.Search.Tweets (https://github.com/tpetricek/Documents/blob/master/Samples/Twitter.API/Twitter.fs#L284), the return type of that is one of the domain types of TwitterTypes.SearchTweets, which is a type alias for JsonProvider<"references\\search_tweets.json"> (https://github.com/tpetricek/Documents/blob/master/Samples/Twitter.API/Twitter.fs#L183).
Although in the tooltip it shows up as JsonProvider<...>.DomainTypes.Url, you'll have to use the type alias TwitterTypes.SearchTweets.DomainTypes.Url
I had a similar problem trying to figure out how to use the FSharp.Data HtmlProvider.
I am using Wikipedia to get information about USA presidents. The HtmlProvider does a great job of discovering the various tables in that webpage, but I wanted to extract the logic for processing a row of "president data" into a separate function called processRow.
And the problem was trying to work out what the type of such a row is for processRow's parameter row. The following code does the trick:
#load "Scripts\load-references.fsx"
open FSharp.Data
let presidents = new HtmlProvider<"https://en.wikipedia.org/wiki/List_of_Presidents_of_the_United_States">()
let ps = presidents.Tables.``List of presidents``
ps.Headers |> Option.map (fun hs -> for h in hs do printf "%s " h)
printfn ""
type Presidents = ``HtmlProvider,Sample="https://en.wikipedia.org/wiki/List_of_Presidents_of_the_United_States"``.ListOfPresidents
let processRow (row:Presidents.Row) =
printfn "%d %s" row.``№`` row.President2
ps.Rows |> Seq.iter processRow
I did not type in the long type alias for Presidents, I used Visual Studio auto-completion by guessing that the type for List of presidents would be discoverable from something starting with Html, and it was, complete with the four single back quotes.

Why can't WSDL type provider disambiguate overload?

From
#r "FSharp.Data.TypeProviders"
#r "System.ServiceModel"
open Microsoft.FSharp.Data.TypeProviders
[<Literal>]
let serviceAddress = "http://localhost/Microsoft/Dynamics/GP/eConnect/mex"
type Dynamics = WsdlService<serviceAddress>
type DynTypes = Dynamics.ServiceTypes.SimpleDataContextTypes
type Address = System.ServiceModel.EndpointAddress
No matter what I do WSDL type provider can't disambiguate the function call:
let svc: DynTypes.eConnectClient = Dynamics.GeteConnectServiceEndpoint()
let svc2 = (Dynamics.GeteConnectServiceEndpoint : unit -> DynTypes.eConnectClient)()
let svc3 = (Dynamics.GeteConnectServiceEndpoint : Address -> DynTypes.eConnectClient)(Address serviceAddress)
None of them works.
Disabling the other Endpoints and leaving only the one for eConnectClient solves the problem, but I don't even know if I may end up needing the other endpoints.
Not familiar with the schema or the type provider, but overloads are not supported by WSDL standard. If the WSDL is generated at runtime from the implementation (as is often the case), the runtime might produce such an invalid WSDL.
I was able to get past this problem by using reflection to find the method I wanted to invoke, and invoked it dynamically.
let noteServiceType = typedefof<NoteService>
let creatorMethod =
noteServiceType.GetMethods()
|> Seq.filter (fun staticMethod ->
staticMethod.Name = "GetCustomBinding_IIntakeNoteManager"
&& staticMethod.ReturnType = typedefof<NoteService.ServiceTypes.SimpleDataContextTypes.IntakeNoteManagerClient>
&& staticMethod.GetParameters().Length = 0)
|> Seq.toList
let creatorMethod = creatorMethod |> Seq.head
let client = creatorMethod.Invoke(null, [||]) :?> NoteService.ServiceTypes.SimpleDataContextTypes.IntakeNoteManagerClient

Is it possible to create an object expression at runtime? [duplicate]

How do I execute F# code from a string in a compiled F# program?
Here's a little script that uses the FSharp CodeDom to compile a string into an assembly and dynamically load it into the script session.
It uses a type extension simply to allow useful defaults on the arguments (hopefully let bound functions will support optional, named and params arguments in the near future.)
#r "FSharp.Compiler.dll"
#r "FSharp.Compiler.CodeDom.dll"
open System
open System.IO
open System.CodeDom.Compiler
open Microsoft.FSharp.Compiler.CodeDom
let CompileFSharpString(str, assemblies, output) =
use pro = new FSharpCodeProvider()
let opt = CompilerParameters(assemblies, output)
let res = pro.CompileAssemblyFromSource( opt, [|str|] )
if res.Errors.Count = 0 then
Some(FileInfo(res.PathToAssembly))
else None
let (++) v1 v2 = Path.Combine(v1, v2)
let defaultAsms = [|"System.dll"; "FSharp.Core.dll"; "FSharp.Powerpack.dll"|]
let randomFile() = __SOURCE_DIRECTORY__ ++ Path.GetRandomFileName() + ".dll"
type System.CodeDom.Compiler.CodeCompiler with
static member CompileFSharpString (str, ?assemblies, ?output) =
let assemblies = defaultArg assemblies defaultAsms
let output = defaultArg output (randomFile())
CompileFSharpString(str, assemblies, output)
// Our set of library functions.
let library = "
module Temp.Main
let f(x,y) = sin x + cos y
"
// Create the assembly
let fileinfo = CodeCompiler.CompileFSharpString(library)
// Import metadata into the FSharp typechecker
#r "0lb3lphm.del.dll"
let a = Temp.Main.f(0.5 * Math.PI, 0.0) // val a : float = 2.0
// Purely reflective invocation of the function.
let asm = Reflection.Assembly.LoadFrom(fileinfo.Value.FullName)
let mth = asm.GetType("Temp.Main").GetMethod("f")
// Wrap weakly typed function with strong typing.
let f(x,y) = mth.Invoke(null, [|box (x:float); box (y:float)|]) :?> float
let b = f (0.5 * Math.PI, 0.0) // val b : float = 2.0
To use this in a compiled program you would need the purely reflective invocation.
Of course this is a toy compared to a full scripting API that many of us in the community have urgently requested.
best of luck,
Danny
Are you looking for an Eval function?
You might want to try looking at this blog post:
http://fsharpnews.blogspot.com/2007/02/symbolic-manipulation.html
If you read in your expressions into these kind of symbolic datastructures, they are pretty easy to evaluate.
Or, perhaps you are looking for scripting support:
http://blogs.msdn.com/chrsmith/archive/2008/09/12/scripting-in-f.aspx
If you really want dynamic compilation, you could do it with the F# CodeDom provider.
There has been movement on this front. You can now compile using the FSharp.Compiler.Service
simple sample using FSharp.Compiler.Service 5.0.0 from NuGet
open Microsoft.FSharp.Compiler.SimpleSourceCodeServices
let compile (codeText:string) =
let scs = SimpleSourceCodeServices()
let src,dllPath =
let fn = Path.GetTempFileName()
let fn2 = Path.ChangeExtension(fn, ".fs")
let fn3 = Path.ChangeExtension(fn, ".dll")
fn2,fn3
File.WriteAllText(src,codeText)
let errors, exitCode = scs.Compile [| "fsc.exe"; "-o"; dllPath; "-a";src; "-r"; "WindowsBase"; "-r" ;"PresentationCore"; "-r"; "PresentationFramework" |]
match errors,exitCode with
| [| |],0 -> Some dllPath
| _ ->
(errors,exitCode).Dump("Compilation failed")
File.Delete src
File.Delete dllPath
None
then it's a matter of Assembly.LoadFrom(dllPath) to get it into the current app domain.
followed by reflection based-calls into the dll (or possibly Activator.CreateInstance)
Sample LinqPad Usage

printf style logging for f#

How do i setup a printf-style logger for f# using logging library similar to log4net.
i have Log.Debug, Info, Warn, etc. functions that are similar to DebugFormat or InfoFormat in log4net. i tried to setup type extensions for my Log class that i could call in printf style like Log.Debugf "%s" "foo". my generic log function looks like this:
let log format = Printf.kprintf (sprintf "%s") format
i am having trouble with the extension function signature to log to my Debug function...
i tried using Debugf format and Debug
I'm not familiar with log4net, but assuming you're logging to a MessageBox (like the pros do), you can do the following:
let log format = Printf.kprintf (fun msg -> System.Windows.Forms.MessageBox.Show(msg)) format
In this case, since Show takes a string, it can be shortened to:
let log format = Printf.kprintf System.Windows.Forms.MessageBox.Show format
you mean something like this ?
open System
type SomeLogger() =
member this.Error(format : string, [<ParamArray>]args : obj[] ) = ()
member this.Info(format : string, [<ParamArray>]args : obj[] ) = ()
module Extensions =
type SomeLogger with
member this.FInfo format = Printf.ksprintf (this.Info) format
member this.FError format = Printf.ksprintf (this.Error) format
open Extensions
let l = new SomeLogger()
l.FInfo "%d%s" 10 "123"
You can use standard logging subsystem that defined in System.Diagnostic namespace.
You shall be sure that your logging enviromnet correctly initialized. For example something like this (part of example in C#) but it easy is linked with f# code.
Trace.Listeners.Clear();
try {
TextWriterTraceListener infoTextLogger = new AlignedTextWriterTraceListener(#"c:\temp\log.log");
infoTextLogger.Filter = new EventTypeFilter(SourceLevels.All);
infoTextLogger.TraceOutputOptions = TraceOptions.DateTime | TraceOptions.ProcessId | TraceOptions.ThreadId;
Trace.Listeners.Add(infoTextLogger);
TextWriterTraceListener consoleWriter = new AlignedTextWriterTraceListener(System.Console.Out);
consoleWriter.Filter = new EventTypeFilter(SourceLevels.Information);
Trace.Listeners.Add(consoleWriter);
} catch (Exception exp) {
throw exp;
}
AlignedTextWriterTraceListener.TraceSourceNameLength = SOURCE_NAME_FIELD_LENGTH;
Trace.AutoFlush = true;
Trace.TraceInformation("Logging subsystem has been initiated");
so in f#
open System
open System.Diagnostics
module ClientConsole =
let Run _ =
Trace.TraceInformation("Client started");
For more convenient you can use another trace listener that definded by third party programmer.
For example lool at : AlignedTextWriterTraceListener

Resources